diff --git a/.gitignore b/.gitignore index c2065bc..fa4550f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,8 @@ out/ ### VS Code ### .vscode/ + +### DB 비밀번호 ### +/src/main/resources/db.properties +/src/test/java/com/web/mzvoca/repository/DBConst.java +/src/main/resources/application-db.properties diff --git a/build.gradle b/build.gradle index cb4b4ae..bc83ee5 100644 --- a/build.gradle +++ b/build.gradle @@ -25,8 +25,17 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' + + // 테스트코드 @Slf4j 사용 + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' + + // JDBC, MySQL + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + runtimeOnly 'com.mysql:mysql-connector-j' } tasks.named('test') { diff --git a/settings.gradle b/settings.gradle index b3cb5b6..b3a94c1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ -rootProject.name = 'mzvoca' +rootProject.name = 'mzvoca' + + '' diff --git a/src/main/java/com/web/mzvoca/controller/QuizController.java b/src/main/java/com/web/mzvoca/controller/QuizController.java new file mode 100644 index 0000000..a0d9644 --- /dev/null +++ b/src/main/java/com/web/mzvoca/controller/QuizController.java @@ -0,0 +1,22 @@ +package com.web.mzvoca.controller; + +import com.web.mzvoca.dto.AnswerDTO; +import com.web.mzvoca.dto.RequestDto; +import com.web.mzvoca.service.QuizService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api") +public class QuizController { + + private final QuizService quizService; + + @PostMapping("/wrongRate") + public List getWrongRate(@RequestBody List requestDtos) { + return quizService.getWrongCountRate(requestDtos); + } +} diff --git a/src/main/java/com/web/mzvoca/dto/AnswerDTO.java b/src/main/java/com/web/mzvoca/dto/AnswerDTO.java new file mode 100644 index 0000000..ef504a3 --- /dev/null +++ b/src/main/java/com/web/mzvoca/dto/AnswerDTO.java @@ -0,0 +1,13 @@ +package com.web.mzvoca.dto; + +import lombok.Data; + +@Data +public class AnswerDTO { + + private final int questionNumber; //문제 번호를 나타내는 정수형 변수 + private final double wrongCountRate; //오답률은 0과 1 사이의 값으로, 1에 가까울수록 오답률이 높다는 것을 의미합니다. + +} + +//AnswerDTO는 주로 문제 번호와 해당 문제의 오답률을 전송하는 데 사용 \ No newline at end of file diff --git a/src/main/java/com/web/mzvoca/dto/QuizDTO.java b/src/main/java/com/web/mzvoca/dto/QuizDTO.java new file mode 100644 index 0000000..24cdfcd --- /dev/null +++ b/src/main/java/com/web/mzvoca/dto/QuizDTO.java @@ -0,0 +1,19 @@ +package com.web.mzvoca.dto; + +import lombok.Data; + +@Data +public class QuizDTO { + private Long questionNumber; //문제 번호를 나타내는 Long 타입의 변수 + private String q; // 문제 내용을 나타내는 문자열 + private AnswerOption[] a; // 답안 옵션을 나타내는 AnswerOption 배열입니다. + private String c; // : 문제에 대한 해설을 나타내는 문자열입니다. + + @Data + public static class AnswerOption { + private String answer; //답안의 내용을 나타내는 문자열입니다. + private int[] type; // 답안의 유형을 나타내는 정수 배열 + } +} + +//QuizDTO는 주로 퀴즈 문제의 내용, 답안 옵션, 해설 등의 정보를 전송하는 데 사용 diff --git a/src/main/java/com/web/mzvoca/dto/RequestDto.java b/src/main/java/com/web/mzvoca/dto/RequestDto.java new file mode 100644 index 0000000..21aa44b --- /dev/null +++ b/src/main/java/com/web/mzvoca/dto/RequestDto.java @@ -0,0 +1,12 @@ +package com.web.mzvoca.dto; + +import lombok.Data; + +@Data +public class RequestDto { + private int questionNumber; //문제 번호를 나타내는 정수 필드 + private int selectedAnswer; //선택된 답변의 번호나 값을 나타내는 정수 필드 + private boolean tf; // 참/거짓 값을 나타내는 불린 필드 + private int section; //섹션 번호나 구분을 나타내는 정수 필드 +} +//RequestDto는 클라이언트에서 서버로 보내는 요청 데이터의 구조를 정의 \ No newline at end of file diff --git a/src/main/java/com/web/mzvoca/repository/ConnectionConst.java b/src/main/java/com/web/mzvoca/repository/ConnectionConst.java new file mode 100644 index 0000000..9ad7163 --- /dev/null +++ b/src/main/java/com/web/mzvoca/repository/ConnectionConst.java @@ -0,0 +1,7 @@ +package com.web.mzvoca.repository; + +public abstract class ConnectionConst { + public static final String URL = ""; + public static final String userName = "root"; + public static final String password = ""; +} diff --git a/src/main/java/com/web/mzvoca/repository/QuestionRepository.java b/src/main/java/com/web/mzvoca/repository/QuestionRepository.java new file mode 100644 index 0000000..e4e6148 --- /dev/null +++ b/src/main/java/com/web/mzvoca/repository/QuestionRepository.java @@ -0,0 +1,8 @@ +package com.web.mzvoca.repository; + +public interface QuestionRepository { + + public int questionWrongCountRead(int questionNumber); + + public void questionWrongCountUpdate(int questionNumber); +} diff --git a/src/main/java/com/web/mzvoca/repository/QuestionRepositoryImpl.java b/src/main/java/com/web/mzvoca/repository/QuestionRepositoryImpl.java new file mode 100644 index 0000000..f550df0 --- /dev/null +++ b/src/main/java/com/web/mzvoca/repository/QuestionRepositoryImpl.java @@ -0,0 +1,86 @@ +package com.web.mzvoca.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; +import javax.xml.transform.Result; +import java.sql.*; +import java.util.NoSuchElementException; + +@RequiredArgsConstructor +@Repository +public class QuestionRepositoryImpl implements QuestionRepository { + + private final DataSource dataSource; + + /** + * @return 특정 문항의 "wrong_count"를 반환 + */ + @Override + public int questionWrongCountRead(int questionNumber) { +// wrong_count 컬럼 조회 - where PK 값으로"; + String sql = "select wrong_count from question where question_number = ?"; + + Connection con = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + // Datasource로부터 커넥션을 가져온 뒤, 쿼리문을 실행하여 ResultSet에 반환 + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setInt(1, questionNumber); + rs = pstmt.executeQuery(); + + if (rs.next()) { + return rs.getInt("wrong_count"); + } else { + throw new NoSuchElementException("wrong_count 값이 없습니다."); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + close(con, pstmt, rs); + } + } + + /** + * 특정 문제의 오답 횟수를 1 증가 + */ + @Override + public void questionWrongCountUpdate(int questionNumber) { + // wrongCount UPDATE where PK = questionNumber + String sql = "update question set wrong_count = wrong_count + 1 where question_number = ?"; + + Connection con = null; + PreparedStatement pstmt = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + pstmt.setInt(1, questionNumber); + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + close(con, pstmt, null); + } + } + + private Connection getConnection() throws SQLException { + // 트랜잭션 동기화를 위해 DataSourceUtils 메서드 사용 + Connection con = DataSourceUtils.getConnection(dataSource); + return con; + } + + private void close(Connection con, Statement stmt, ResultSet rs) { + JdbcUtils.closeResultSet(rs); + JdbcUtils.closeStatement(stmt); + // 트랜잭션 동기화를 위해 DataSourceUtils 메서드 사용 + DataSourceUtils.releaseConnection(con, dataSource); + } +} diff --git a/src/main/java/com/web/mzvoca/repository/TotalCountRepository.java b/src/main/java/com/web/mzvoca/repository/TotalCountRepository.java new file mode 100644 index 0000000..43ad4c9 --- /dev/null +++ b/src/main/java/com/web/mzvoca/repository/TotalCountRepository.java @@ -0,0 +1,8 @@ +package com.web.mzvoca.repository; + +public interface TotalCountRepository { + + public int totalCountRead(); + + public void totalCountUpdate(); +} diff --git a/src/main/java/com/web/mzvoca/repository/TotalCountRepositoryImpl.java b/src/main/java/com/web/mzvoca/repository/TotalCountRepositoryImpl.java new file mode 100644 index 0000000..750ac1e --- /dev/null +++ b/src/main/java/com/web/mzvoca/repository/TotalCountRepositoryImpl.java @@ -0,0 +1,86 @@ +package com.web.mzvoca.repository; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; +import java.sql.*; +import java.util.NoSuchElementException; + +@Repository +@RequiredArgsConstructor +@Slf4j +public class TotalCountRepositoryImpl implements TotalCountRepository { + + private final DataSource dataSource; + + /** + * @return 현재 제출된 횟수를 반환 + */ + @Override + public int totalCountRead() { + String sql = "select * from totalcount"; + + Connection con = null; + PreparedStatement pstmt = null; + ResultSet rs = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + rs = pstmt.executeQuery(); + if (rs.next()) { + // 가져온 데이터가 있을 때 실행할 부분 + int totalCount = rs.getInt("total_count"); + return totalCount; + } else { + throw new NoSuchElementException("값이 없습니다."); + } + + } catch (SQLException e) { + throw new RuntimeException(e); + } finally { + close(con, pstmt, rs); + } + } + + /** + * 현재 제출 횟수에서 +1하는 메서드 + */ + @Override + public void totalCountUpdate() { + // Update문을 통해 totalCount 값을 1 증가 + String sql = "update totalcount set total_count = total_count + 1"; + + Connection con = null; + PreparedStatement pstmt = null; + + try { + con = getConnection(); + pstmt = con.prepareStatement(sql); + int result = pstmt.executeUpdate(); + log.info("실행된 행 개수={}", result); + } catch (SQLException e) { + log.info("db Error", e); + throw new RuntimeException(e); + } finally { + close(con, pstmt, null); + } + } + + private Connection getConnection() throws SQLException { + // 트랜잭션 동기화를 위해 DataSourceUtils 메서드 사용 + Connection con = DataSourceUtils.getConnection(dataSource); + return con; + } + + private void close(Connection con, Statement stmt, ResultSet rs) { + JdbcUtils.closeResultSet(rs); + JdbcUtils.closeStatement(stmt); + // 트랜잭션 동기화를 위해 DataSourceUtils 메서드 사용 + DataSourceUtils.releaseConnection(con, dataSource); + } +} diff --git a/src/main/java/com/web/mzvoca/service/QuizService.java b/src/main/java/com/web/mzvoca/service/QuizService.java new file mode 100644 index 0000000..8e4ba70 --- /dev/null +++ b/src/main/java/com/web/mzvoca/service/QuizService.java @@ -0,0 +1,11 @@ +package com.web.mzvoca.service; + +import com.web.mzvoca.dto.AnswerDTO; +import com.web.mzvoca.dto.RequestDto; +import java.util.List; + +public interface QuizService { + List getWrongCountRate(List requestDtos); +} +//매개변수: List requestDtos - 사용자의 답변과 관련된 정보를 포함하는 RequestDto 객체의 목록 +//반환 타입: List - 각 문제에 대한 잘못된 답변 비율을 포함하는 AnswerDTO 객체의 목록 diff --git a/src/main/java/com/web/mzvoca/service/QuizServiceImpl.java b/src/main/java/com/web/mzvoca/service/QuizServiceImpl.java new file mode 100644 index 0000000..3fcea7c --- /dev/null +++ b/src/main/java/com/web/mzvoca/service/QuizServiceImpl.java @@ -0,0 +1,37 @@ +package com.web.mzvoca.service; + +import com.web.mzvoca.dto.AnswerDTO; +import com.web.mzvoca.dto.RequestDto; +import com.web.mzvoca.repository.QuestionRepository; +import com.web.mzvoca.repository.TotalCountRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class QuizServiceImpl implements QuizService { + + private final TotalCountRepository totalCountRepository; + private final QuestionRepository questionRepository; + + @Override + public List getWrongCountRate(List requestDtos) { + int totalCount = totalCountRepository.totalCountRead();//전체 제출 횟수를 조회합니다. + List answerDTOList = new ArrayList<>(); +//사용자의 답변을 기반으로 각 문제의 잘못된 답변 비율을 계산 + for (RequestDto requestDto : requestDtos) { + int questionNumber = requestDto.getQuestionNumber(); + int wrongCount = questionRepository.questionWrongCountRead(questionNumber); + //사용자의 답변 목록을 순회하면서 각 문제의 잘못된 답변 횟수를 조회합니다. + double wrongRate = (double) wrongCount / totalCount; + answerDTOList.add(new AnswerDTO(questionNumber, wrongRate)); + } + //잘못된 답변 비율을 계산하고, 이를 AnswerDTO 객체에 저장합니다. + //계산된 AnswerDTO 객체를 목록에 추가합니다. + + return answerDTOList; + //반환 값: 각 문제에 대한 잘못된 답변 비율을 포함하는 AnswerDTO 객체의 목록 + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8b13789..63383a3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,2 @@ - +# DB ?? ?? +spring.profiles.include = db diff --git a/src/main/resources/static/css/main.css b/src/main/resources/static/css/main.css new file mode 100644 index 0000000..d134b0d --- /dev/null +++ b/src/main/resources/static/css/main.css @@ -0,0 +1,89 @@ +.mainbody{ + background: url("../images/v1_3.png"); + text-align: center; + background-size:cover; + height:100dvh; + margin: 0 auto; +} +body{ + background-color: pink; + margin: 0; + padding: 0; +} +ul{ + border: 1px solid; + text-align:left +} +.name{ + display: flex; + justify-content: center; /* 수평 가운데 정렬 */ + align-items: center; /* 수직 가운데 정렬 */ + text-align: center; +} + +th{ + border: 1px solid; +} +.btn1{ + background-color: gray; + color:black; +} +*{ + font-family: 'Noto Serif KR', serif; +} +@media (min-width: 1024px) { + .mainbody { + height: 100dvh; + width: 864px; + min-width: 864px; + font-size: 140px; + + } + .container{ + display: flex; + justify-content: center; /* 수평 가운데 정렬 */ + align-items: center; /* 수직 가운데 정렬 */ + text-align: center; + } + /* PC에 대한 추가 스타일 */ +} +@media all and (min-width:768px) and (max-width:1023px) { + .mainbody { + height: 100dvh; + width: 100dvw; + font-size: 140px; + padding:0; + margin:0; + } + .container{ + padding:0; + margin:0; + } + } + /*태블릿*/ + +/* 모바일 스타일 */ +@media (max-width: 767px) { + .mainbody { + height: 100dvh; + width: 100dvw; + font-size:11vh; + } + .container { + padding:0; + margin:0; + } + +} +@media (min-width: 280px)and (max-width: 319px) and (orientation: portrait) { + .mainbody { + height: 100%; + width: 100dvw; + font-size:80px; + } + .container { + padding:0; + margin:0; + } +} +/*갤럭시폴드*/ \ No newline at end of file diff --git a/src/main/resources/static/css/questions.css b/src/main/resources/static/css/questions.css new file mode 100644 index 0000000..875fc5b --- /dev/null +++ b/src/main/resources/static/css/questions.css @@ -0,0 +1,117 @@ +#qna{ + display: none; +} +#result{ + display:none; +} +#commentary{ + display: none; +} +#ranking{ + display: none; +} +.mainbody{ + background: url("../images/v1_3.png"); + text-align: center; + background-size:cover; + height:100dvh; + margin: 0 auto; + +} + +.questionstyle{ + font-size: 0.30em; +} +.answerstyle{ + font-size: 0.24em; + text-align: left; +} +.commentarystyle{ + font-size:0.18em; +} +body{ + background-color: pink; + margin: 0; + padding: 0; +} + +.btn1{ + background-color: gray; + color:black; +} +*{ + font-family: 'Noto Serif KR', serif; +} +.answerbutton{ + border-radius: 50%; + width: 33.6px; + height: 33.6px; + display: flex; + justify-content: center; + align-items: center; + float: left; +} +.answerbutton:active{ + background-color: red; +} + + +@media (min-width: 1024px) { + .mainbody { + height: 100dvh; + width: 864px; + min-width: 864px; + font-size: 140px; + + } + .container{ + display: flex; + justify-content: center; /* 수평 가운데 정렬 */ + align-items: center; /* 수직 가운데 정렬 */ + text-align: center; + } + /* PC에 대한 추가 스타일 */ +} +@media all and (min-width:768px) and (max-width:1023px) { + .mainbody { + height: 100dvh; + width: 100dvw; + font-size: 140px; + padding:0; + margin:0; + + } + .container{ + padding:0; + margin:0; + } + } + /*태블릿*/ + +/* 모바일 스타일 */ +@media (max-width: 767px) { + .mainbody { + height: 100dvh; + width: 100dvw; + font-size:11vh; + + } + .container { + padding:0; + margin:0; + } + +} +@media (min-width: 280px)and (max-width: 319px) and (orientation: portrait) { + .mainbody { + height: 100%; + width: 100dvw; + font-size:80px; + + } + .container { + padding:0; + margin:0; + } +} +/*갤럭시폴드*/ \ No newline at end of file diff --git a/src/main/resources/static/images/icon/copy.png b/src/main/resources/static/images/icon/copy.png new file mode 100644 index 0000000..90dbfa2 Binary files /dev/null and b/src/main/resources/static/images/icon/copy.png differ diff --git a/src/main/resources/static/images/icon/icon-facebook.png b/src/main/resources/static/images/icon/icon-facebook.png new file mode 100644 index 0000000..bb925b7 Binary files /dev/null and b/src/main/resources/static/images/icon/icon-facebook.png differ diff --git a/src/main/resources/static/images/icon/icon-instagram.png b/src/main/resources/static/images/icon/icon-instagram.png new file mode 100644 index 0000000..1f2b90e Binary files /dev/null and b/src/main/resources/static/images/icon/icon-instagram.png differ diff --git a/src/main/resources/static/images/icon/icon-kakao.png b/src/main/resources/static/images/icon/icon-kakao.png new file mode 100644 index 0000000..4921bcf Binary files /dev/null and b/src/main/resources/static/images/icon/icon-kakao.png differ diff --git a/src/main/resources/static/images/icon/icon-twitter.png b/src/main/resources/static/images/icon/icon-twitter.png new file mode 100644 index 0000000..7a5fcc9 Binary files /dev/null and b/src/main/resources/static/images/icon/icon-twitter.png differ diff --git a/src/main/resources/templates/images/v1_3.png b/src/main/resources/static/images/v1_3.png similarity index 100% rename from src/main/resources/templates/images/v1_3.png rename to src/main/resources/static/images/v1_3.png diff --git a/src/main/resources/static/js/data.js b/src/main/resources/static/js/data.js new file mode 100644 index 0000000..5cdeb14 --- /dev/null +++ b/src/main/resources/static/js/data.js @@ -0,0 +1,152 @@ +const qnaList=[ + { + q : '1. 다음 중 "금일" 의 뜻으로 알맞은 것은?', + a : [ + {answer: '금요일', type:[0]}, + {answer: '오늘', type:[0]}, + {answer: '내일', type:[0]}, + {answer: '이틀 후', type:[0]}, + ], + c : "해설: '금일' 은 지금 지나가고 있는 이날, 즉 (2) 오늘 을 뜻합니다.", + }, + { + q : '2. 다음 중 화가 났을때 사용하는 밈(Meme)과 관련이 없는 것은?', + a : [ + {answer: 'kg받네'}, + {answer: '군싹'}, + {answer: '킹받드라슈'}, + {answer: '쫑받네'}, + ], + c: "해설: '군싹' 은 \"군침이 싹 도노\" 라는 의미로, 화가 났을 때 사용하는 밈과 거리가 멉니다." + }, + { + q : '3. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '4. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '5. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '6. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '7. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '8. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '9. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '10. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '11. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '12. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '13. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '14. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, + { + q : '15. test', + a : [ + {answer: '1번 답'}, + {answer: '2번 답'}, + {answer: '3번 답'}, + {answer: '4번 답'}, + ], + c: "해설: test", + }, +] \ No newline at end of file diff --git a/src/main/resources/static/js/start.js b/src/main/resources/static/js/start.js new file mode 100644 index 0000000..552a167 --- /dev/null +++ b/src/main/resources/static/js/start.js @@ -0,0 +1,344 @@ +const main=document.querySelector('#main'); +const qna=document.querySelector('#qna'); +const result=document.querySelector('#result'); +const commentary=document.querySelector('#commentary'); +const ranking=document.querySelector('#ranking'); +const select=[]; +const button1 = document.querySelector('.button1'); +const button2 = document.querySelector('.button2'); +const button3 = document.querySelector('.button3'); +const button4 = document.querySelector('.button4'); +const answer=[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; +var qIdx=0; +var score=0; +var mzscore=0; +var Grade; +var Mzgrade; +var Percentile; +var Mzpercentile; +var Stscore; +var Mzstscore; +button1.addEventListener('click', function() { + var sec; + if((qIdx+1)%3){ + sec=0; + } + else{ + sec=1; + } + if(answer[qIdx]==1){ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 1 , tf: true, section: sec }); + } + else{ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 1 , tf: false, section: sec}); + } +}); + +button2.addEventListener('click', function() { + var sec; + if((qIdx+1)%3){ + sec=0; + } + else{ + sec=1; + } + if(answer[qIdx]==2){ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 2 , tf: true, section: sec}); + } + else{ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 2 , tf: false, section: sec}); + } +}); + +button3.addEventListener('click', function() { + var sec; + if((qIdx+1)%3){ + sec=0; + } + else{ + sec=1; + } + if(answer[qIdx]==3){ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 3 , tf: true, section: sec}); + } + else{ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 3 , tf: false, section: sec}); + } +}); + +button4.addEventListener('click', function() { + var sec; + if((qIdx+1)%3){ + sec=0; + } + else{ + sec=1; + } + if(answer[qIdx]==4){ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 4 , tf: true, section: sec}); + } + else{ + select.push({ questionNumber: qIdx + 1, selectedAnswer: 4 , tf: false, section: sec}); + } +}); + +function calResult(){ + var sec; + if((qIdx+1)%3){ + sec=0; + } + else{ + sec=1; + } + for(i=0; i<15; i++){ + if(select[i]&&select[i].tf===true){ + if(select[i].section==0){ + score+=10; + } + else{ + mzscore+=20; + } + } + } +} +function calGrade(){ + if(score<=10){ + Grade=9; + Percentile=98; + Stscore=43; + } + else if (score<=20){ + Grade=8; + Percentile=91; + Stscore=67; + } + else if (score<=30){ + Grade=7; + Percentile=83; + Stscore=79; + } + else if (score<=40){ + Grade=6; + Percentile=68; + Stscore=91; + } + else if (score<=50){ + Grade=5; + Percentile=53; + Stscore=102; + } + else if (score<=60){ + Grade=4; + Percentile=31; + Stscore=109; + } + else if (score<=70){ + Grade=3; + Percentile=17; + Stscore=121; + } + else if (score<=80){ + Grade=2; + Percentile=6; + Stscore=127; + } + else{ + Grade=1; + Percentile=1; + Stscore=139; + } + if(mzscore<20){ + Mzgrade=9; + Mzpercentile=99; + Mzstscore=51; + } + else if (mzscore<40){ + Mzgrade=7; + Mzpercentile=81; + Mzstscore=76; + } + else if (mzscore<60){ + Mzgrade=5; + Mzpercentile=45; + Mzstscore=102; + } + else if (mzscore<80){ + Mzgrade=3; + Mzpercentile=13; + Mzstscore=121; + } + else{ + Mzgrade=1; + Mzpercentile=1; + Mzstscore=134; + } +} + +function next(){ + goNext(++qIdx); +} +function prev(){ + if(qIdx==0){ + qna.style.display="none"; + main.style.display="block"; + } + else{ + goNext(--qIdx); + } +} +function goFirst(){ + result.style.display="none"; + main.style.display="block"; +} + +function getPost(){ + $.ajax({ + url:"http://localhost:8080/api/wrongRate", + type:"POST", + data:JSON.stringify(select), + contentType: "application/json", + success: function(result) { + if (result) { + alert("저장되었습니다."); + console.log(JSON.stringify(result)); + } else { + alert("잠시 후에 시도해주세요."); + } + }, + error: function() { + alert("에러 발생"); + } + }) +} + +function goNext(qIdx){ + var q=document.querySelector('.qBox'); + var a1=document.querySelector('.a1'); + var a2=document.querySelector('.a2'); + var a3=document.querySelector('.a3'); + var a4=document.querySelector('.a4'); + var section=document.querySelector('.section'); + var status=document.querySelector('.status'); + var statusBar=document.querySelector('.statusBar'); + var stscore=document.querySelector('.stscore'); + var mzstscore=document.querySelector('.mzstscore'); + var percentile=document.querySelector('.percentile'); + var mzpercentile=document.querySelector('.mzpercentile'); + var grade=document.querySelector('.grade'); + var mzgrade=document.querySelector('.mzgrade'); + if(qIdx===qnaList.length){ + qna.style.display="none"; + result.style.display="block"; + getPost(); + calResult(); + calGrade(); + grade.innerHTML=Grade; + mzgrade.innerHTML=Mzgrade; + stscore.innerHTML=Stscore; + mzstscore.innerHTML=Mzstscore; + percentile.innerHTML=Percentile; + mzpercentile.innerHTML=Mzpercentile; + } + if(qIdx%2==0){ + section.innerHTML='문해력 영역'; + } + else{ + section.innerHTML='MZ 영역'; + } + status.innerHTML=qIdx+1+'/15'; + statusBar.style.width=((qIdx+1)/15*100)+'%'; + q.innerHTML=qnaList[qIdx].q; + a1.innerHTML=qnaList[qIdx].a[0].answer; + a2.innerHTML=qnaList[qIdx].a[1].answer; + a3.innerHTML=qnaList[qIdx].a[2].answer; + a4.innerHTML=qnaList[qIdx].a[3].answer; +} + +function begin(){ + qIdx=0; + score=0; + main.style.display="none"; + qna.style.display="block"; + goNext(qIdx); +} +const qnaContainer= document.getElementById('qnacontainer'); +function goCommentary(){ + qnaList.forEach((qna,Index)=>{ + addQnA(qna,Index); + }); + result.style.display="none"; + commentary.style.display="block"; +} +function addQnA(qna,Index){ + const qElement = document.createElement('div'); + qElement.classList.add('questionstyle'); + qElement.classList.add('m-5'); + qElement.textContent=qna.q; + qnaContainer.appendChild(qElement); + + qna.a.forEach((answer,index)=>{ + const aElement=document.createElement('div'); + aElement.classList.add('answerstyle'); + aElement.classList.add('col-8'); + aElement.classList.add('mx-auto'); + aElement.textContent = `${index + 1}. ${answer.answer}`; + qnaContainer.appendChild(aElement); + }); + + const sElement=document.createElement('div'); + sElement.classList.add('commentarystyle'); + sElement.classList.add('m-5'); + if (select[Index] && typeof select[Index].selectedAnswer !== 'undefined') { + sElement.textContent='선택한 답: '+select[Index].selectedAnswer; + } else { + sElement.textContent ='무응답'; // 또는 다른 기본값 설정 + } + qnaContainer.appendChild(sElement); + + const cElement=document.createElement('div'); + cElement.classList.add('commentarystyle'); + cElement.classList.add('m-5'); + cElement.textContent=qna.c; + qnaContainer.appendChild(cElement); + +} + +function goResult(){ + commentary.style.display="none"; + ranking.style.display="none"; + result.style.display="block"; +} +function goRanking(){ + result.style.display="none"; + ranking.style.display="block"; +} + + +// 현재 페이지 URL 가져오기 +const currentPageURL = window.location.href; + +// 링크 복사 함수 +function copyPageLink() { + const tempInput = document.createElement('input'); + tempInput.value = currentPageURL; + document.body.appendChild(tempInput); + tempInput.select(); + document.execCommand('copy'); + document.body.removeChild(tempInput); +} + +// 카카오톡 공유 함수 +function shareKakao() { + Kakao.Link.sendDefault({ + objectType: 'feed', + content: { + title: '페이지 제목', + description: '페이지 설명', + imageUrl: '이미지 URL', + link: { + mobileWebUrl: currentPageURL, + webUrl: currentPageURL, + }, + }, + }); +} \ No newline at end of file diff --git a/src/main/resources/templates/css/main.css b/src/main/resources/templates/css/main.css deleted file mode 100644 index 4456526..0000000 --- a/src/main/resources/templates/css/main.css +++ /dev/null @@ -1,34 +0,0 @@ - -.mainbody{ - margin-top:10px; - margin-bottom:10px; - padding-top:5px; - background: url("../images/v1_3.png"); - text-align: center; - background-size:cover; - height:90vdh; -} -body{ - background-color: pink; -} -ul{ - border: 1px solid; - text-align:left -} -.name{ - display: flex; - justify-content: center; /* 수평 가운데 정렬 */ - align-items: center; /* 수직 가운데 정렬 */ - text-align: center; -} - -th{ - border: 1px solid; -} -.btn1{ - background-color: gray; - color:black; -} -*{ - font-family: 'Noto Serif KR', serif; -} diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 3974d9b..09049f5 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -5,45 +5,157 @@ Document - + +
-
-
제 2교시
-
2023학년도 MZ어휘력고사 문제지
-
문해력 영역
-
-
- - -
성명김잼민
+
+
+
+
제 2교시
-
- - -
수험번호123-456789
+
2023학년도 MZ어휘력고사 문제지
+
문해력 영역
+
+
+ + +
성명김잼민
+
+
+ + +
수험번호123-456789
+
+
+
    +
  • 자신이 선택한 과목의 문제지인지 확인하시오.
  • +
  • 매 선택과목마다 문제지의 해당란에 성명과 수험번호를 정확히 쓰시오.
  • +
  • 답안지의 필적 확인란에 다음의 문구를 정자로 기재하시오.
    +
    MZ 특: 이런거 자세히 안봄
    +
  • +
  • 답안지의 해당란에 성명과 수험번호를 쓰고, 또 수험번호, 문형(홀수/짝수), 답을 정확히 표시하시오.
  • +
  • 문항에 따라 배점이 같으니 안심하고 푸세요.
  • +
+
+
※ 시험이 시작되기 전까지 표지를 넘기지 마시오.
+ +
한국MZ평가원
-
    -
  • 자신이 선택한 과목의 문제지인지 확인하시오.
  • -
  • 매 선택과목마다 문제지의 해당란에 성명과 수험번호를 정확히 쓰시오.
  • -
  • 답안지의 필적 확인란에 다음의 문구를 정자로 기재하시오.
    -
    MZ 특: 이런거 자세히 안봄
    -
  • -
  • 답안지의 해당란에 성명과 수험번호를 쓰고, 또 수험번호, 문형(홀수/짝수), 답을 정확히 표시하시오.
  • -
  • 문항에 따라 배점이 같으니 안심하고 푸세요.
  • -
-
-
※ 시험이 시작되기 전까지 표지를 넘기지 마시오.
- -
한국MZ평가원
-
+
+
+
+
+
+
+
+
2023학년도 MZ어휘력고사 문제지
+
+
+
+

+

+

+

+
+
+
+ +
+
+ +
+
+
한국MZ평가원
+
+
+
+
+
2023학년도 MZ어휘력고사 성적통지표
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
수험번호성명출신고교
123-45678김잼민MZ고등학교
영역문해력 영역MZ력 영역
선택과목문해력과 맞춤법MZ어
표준점수
백분위
등급
+
2023.08.12
+
한국MZ평가원장
+
+
+ +
+
+ +
+
+ +
+
+
+ + + + + +
+
+
+
+
+
2023학년도 MZ어휘력고사 문제해설
+
+ +
+
+
+
+
오답률 랭킹
+
+
+ + +
- \ No newline at end of file diff --git a/src/main/resources/templates/test.html b/src/main/resources/templates/test.html new file mode 100644 index 0000000..e69de29 diff --git a/src/test/java/com/web/mzvoca/repository/QuestionRepositoryImplTest.java b/src/test/java/com/web/mzvoca/repository/QuestionRepositoryImplTest.java new file mode 100644 index 0000000..53dc29f --- /dev/null +++ b/src/test/java/com/web/mzvoca/repository/QuestionRepositoryImplTest.java @@ -0,0 +1,61 @@ +package com.web.mzvoca.repository; + +import com.zaxxer.hikari.HikariDataSource; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.NoSuchElementException; + +import static com.web.mzvoca.repository.DBConst.*; +import static org.assertj.core.api.Assertions.*; + +class QuestionRepositoryImplTest { + + QuestionRepository questionRepository; + + @BeforeEach + void beforeEach() { + HikariDataSource dataSource = new HikariDataSource(); + dataSource.setJdbcUrl(URL); + dataSource.setUsername(userName); + dataSource.setPassword(password); + + questionRepository = new QuestionRepositoryImpl(dataSource); + } + + + @Test + @DisplayName("특정 문항의 오류 횟수 읽기") + void questionWrongCountRead() { + //given + int questionNumber = 1; + Integer result = null; + + //when + result = questionRepository.questionWrongCountRead(questionNumber); + + //then + assertThat(result).isEqualTo(3); +// assertThatThrownBy(() -> questionRepository.questionWrongCountRead(questionNumber + 3)) +// .isInstanceOf(NoSuchElementException.class); + + } + + @Test + @DisplayName("특정 문항의 오답 횟수 1 증가") + void questionWrongCountUpdate() { + //given + int questionNumber = 1; + Integer beforeResult = questionRepository.questionWrongCountRead(questionNumber); + + //when + questionRepository.questionWrongCountUpdate(questionNumber); + Integer afterResult = questionRepository.questionWrongCountRead(questionNumber); + + //then + assertThat(afterResult).isEqualTo(beforeResult + 1); + + } +} \ No newline at end of file diff --git a/src/test/java/com/web/mzvoca/repository/totalCountRepositoryImplTest.java b/src/test/java/com/web/mzvoca/repository/totalCountRepositoryImplTest.java new file mode 100644 index 0000000..51615c6 --- /dev/null +++ b/src/test/java/com/web/mzvoca/repository/totalCountRepositoryImplTest.java @@ -0,0 +1,57 @@ +package com.web.mzvoca.repository; + +import com.zaxxer.hikari.HikariDataSource; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + + +import static com.web.mzvoca.repository.DBConst.*; +import static org.assertj.core.api.Assertions.*; + +@Slf4j +class totalCountRepositoryImplTest { + + TotalCountRepository totalCountRepository; + + @BeforeEach + void beforeEach() { + HikariDataSource dataSource = new HikariDataSource(); + dataSource.setJdbcUrl(URL); + dataSource.setUsername(userName); + dataSource.setPassword(password); + + totalCountRepository = new TotalCountRepositoryImpl(dataSource); + } + + @Test + @DisplayName("총 제출 횟수 읽기") + void totalCountReadTest() { + //given + Integer result = null; + + //when +// assertThatThrownBy(() -> totalCountRepository.totalCountRead()) +// .isInstanceOf(NoSuchElementException.class); + result = totalCountRepository.totalCountRead(); + + //then + assertThat(result).isEqualTo(3); + + } + + @Test + @DisplayName("총 제출 횟수 1 증가") + void totalCountUpdateTest() { + //given + Integer beforeResult = totalCountRepository.totalCountRead(); + + //when + totalCountRepository.totalCountUpdate(); + Integer afterResult = totalCountRepository.totalCountRead(); + + //then + assertThat(afterResult).isEqualTo(beforeResult + 1); + } +} \ No newline at end of file