-
mvc2( java, jsp, mybatis)LANGUAGE/Java, Spring 2024. 12. 2. 18:45
- mvc2 순서
더보기- Controller 파일에서 url에 command 파라미터에 들어오는 값을 받아줌.
- 시작은 빈 값으로 들어오기 때문에 기본 ListAction / MainAction 등을 만듬.
- 페이지의 데이터를 생성, 수정, 삭제할 때마다 링크를 Controller의 servlet 링크로 연결해서 다른 Action으로 분기 시킴.
- Mapper는 xml 타입의 파일로 쿼리문을 사용해서 DBMS의 데이터를 조작.
- DAO는 Mapper에서 처리한 데이터를 Action으로 옮겨주는 역할.
- Action은 DAO의 메서드를 불러와서 가져온 데이터를 사용 목적에 맞게 조작.
- 이후 Action에서 req.setAttribute를 사용해 view에 위치한 jsp파일에 데이터를 뿌려줌.
- Controller에서 get방식과 post방식을 동시에 처리하는 방법
더보기// 서블릿을 정의하고 "/class.do" URL 패턴에 매핑합니다. @WebServlet("/class.do") public class ClassController extends HttpServlet { // GET 및 POST 요청을 공통으로 처리하는 메서드입니다. private void doProcess(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 요청과 응답의 인코딩을 UTF-8로 설정합니다. req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); // cmd 파라미터를 가져옵니다. String cmd = req.getParameter("cmd"); String url = ""; Action action = null; // cmd 파라미터 값에 따라 적절한 Action 객체를 생성. if (cmd == null || cmd.equals("list")) { action = new ListAction(); // cmd가 없거나 "list"인 경우, 리스트 액션을 수행. } else if (cmd.equals("deleteClass")) { action = new DeleteAction(); // class를 삭제. (delete가 아니라 update로 대체) } else if (cmd.equals("addClass")) { action = new InsertClassAction(); // class를 새로 생성. } else if (cmd.equals("detailClass")) { action = new DetailClassAction(); // class의 세부사항들을 보여줌. (class name, class teacher list, class kid list) } else if (cmd.equals("classKidDelete")) { action = new DeleteKidAction(); // class_kid 삭제 (업데이트) } else if (cmd.equals("classTeacherDelete")) { action = new DeleteTeacherAction(); // class_teacher 삭제 (업데이트) } else if (cmd.equals("updateClassName")) { action = new UpdateClassNameAction(); // class name 업데이트 } else if (cmd.equals("insertClassTeacher")) { action = new InsertClassTeacherAction(); // class_teacer 생성 } else if (cmd.equals("insertKidTeacher")) { action = new InsertClassKidAction(); // class_kid 생성 } // Action 객체의 execute 메서드를 호출하여 해당 작업을 수행하고, 결과 URL을 얻습니다. url = action.execute(req, resp); // 결과 URL로 포워딩합니다. RequestDispatcher rd = req.getRequestDispatcher(url); rd.forward(req, resp); } // GET 요청을 처리합니다. @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doProcess(req, resp); } // POST 요청을 처리합니다. @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doProcess(req, resp); } }
- 조인과 서브쿼리 예시
더보기<!-- 특정 클래스 번호를 통해 해당 클래스에 소속된 모든 선생의 이름과 ID를 조회하는 쿼리 --> <select id="selectAllTeacherByClass" parameterType="int" resultType="HashMap"> SELECT mi.name, mi.id FROM class c JOIN class_teacher ct ON c.class_no = ct.class_no JOIN member_info mi ON ct.class_teacher_id = mi.id JOIN member m ON mi.id = m.id WHERE c.class_no = #{classNo} AND m.inactivate_date IS NULL </select> <!-- 특정 클래스 번호를 통해 해당 클래스에 소속되지 않은 모든 선생의 이름과 ID를 조회하는 쿼리 --> <select id="selectAllTeacherByClassNA" parameterType="int" resultType="HashMap"> SELECT mi.name, mi.id FROM member_info mi WHERE mi.id NOT IN ( SELECT ct.class_teacher_id FROM class_teacher ct JOIN class c ON ct.class_no = c.class_no WHERE c.class_no = #{classNo} ) </select> <!-- 특정 클래스 번호를 통해 해당 클래스에 소속되지 않은 모든 원생의 이름과 번호를 조회하는 쿼리 --> <select id="selectAllKidByClassNA" parameterType="int" resultType="HashMap"> SELECT k.kid_name, k.kid_no FROM kid k WHERE k.kid_no NOT IN ( SELECT ck.kid_no FROM class_kid ck JOIN class c ON ck.class_no = c.class_no WHERE c.class_no = #{classNo} ) AND k.discharge_date IS NULL; </select>
- JSP파일에 Header와 Footer Include하기
더보기<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Attendance Calendar</title> </head> <body> <div class="container mt-5 container-custom"> <!-- 헤더 파일 포함 --> <jsp:include page="/include/header.jsp"></jsp:include> <h1>월간 출석부</h1> <div id='calendar'></div> <!-- 푸터 파일 포함 --> <jsp:include page="/include/footer.jsp"></jsp:include> </div> </body> </html>
- 출석부 페이지에 반 목록 띄우는 방법
더보기- main.jsp 페이지에 있는 달력에서 날짜 선택하면 해당 날짜(detail.jsp)로 이동
- detail.jsp에 class list를 dropdown 형식으로 보여주기 위해 dao에 selectAllClass 메서드 생성
- 해당 메서드에서 xml 형식의 mapper로 이동해서 select 쿼리문을 통해 class list 받아옴
- 다시 detail.jsp에서 req.setAttribute()를 통해 jsp 페이지에 class list 넘겨줌
// DetailTodayAction.java public class DetailTodayAction implements Action { @Override public String execute(HttpServletRequest req, HttpServletResponse resp) { // dao 만들어서 class 목록 가져와서 select-option에서 선택할 수 있도록 for문으로 뿌려줘야 됨 AttendanceDAO adao = new AttendanceDAO(); List<HashMap<String, Object>> classList = adao.selectAllClass(); req.setAttribute("classList", classList); return "views/admin/attendance/detailToday.jsp"; } } // AttendanceDAO.java public List<HashMap<String, Object>> selectAllClass() { SqlSession ss = factory.openSession(true); List<HashMap<String, Object>> list = ss.selectList("kr.co.aico.attendance.selectAllByClass"); System.out.println("class list : " + list); ss.close(); return list; } // attendance.xml <select id="selectAllByClass" resultType="HashMap"> SELECT class_no, class_name, class_age, kinder_no, class_regdate, class_modify_date, class_delete_date FROM class </select>
- 테이블 두개 동시에 생성하기
더보기- 반에 해당하는 class_kid 또는 class_teacher를 생성하기 위해서는 그 전에 accept_log를 생성해야 됨.
- accept_log의 accept_no 컬럼을 받아서 class_kid의 accept_no에 대입.
- accept_log의 accept_delete_date에 날짜를 입력할 경우 class_kid는 view쪽에서 안보이게 처리.
- dao.java에서 메서드를 작성할 때 SqlSession타입의 변수를 factory.openSession(false)로 설정해서 자동 commit을 막음.
- 그리고 쿼리 문을 두 개 작성. (insertAcceptLog, insertKid)
// ClassDAO.java // 특정 클래스 번호와 원생 번호로 새로운 원생 정보를 삽입하는 메서드 public void insertKid(int classNo, int kidNo) { SqlSession ss = factory.openSession(false); HashMap<String, Object> params = new HashMap<String, Object>(); params.put("classNo", classNo); params.put("kidNo", kidNo); // 수락 로그 삽입 ss.insert("kr.co.aico.class.insertAcceptLog", params); // 원생 정보 삽입 ss.insert("kr.co.aico.class.insertKid", params); ss.commit(); ss.close(); } // class.xml <!-- 새로운 수락 로그를 삽입하고 자동 증가된 accept_no 값을 반환하는 쿼리 --> <insert id="insertAcceptLog" keyProperty="accept_no" keyColumn="accept_no" useGeneratedKeys="true" parameterType="HashMap"> INSERT INTO accept_log (accept_date, accept_status) VALUES (now(), 1) </insert> <!-- 새로운 원생 정보를 삽입하는 쿼리 (해당 원생이 이미 존재하지 않는 경우에만) --> <insert id="insertKid" parameterType="HashMap"> INSERT INTO class_kid (class_no, kid_no, accept_no) SELECT #{classNo}, #{kidNo}, #{accept_no} WHERE NOT EXISTS ( SELECT #{kidNo} FROM class_kid WHERE class_no = #{classNo} AND kid_no = #{kidNo} ) </insert>
- full calendar 라이브러리 사용 (jquery 사용해서 날짜 클릭시 해당 날짜로 이동)
더보기$(document).ready(function() { var calendarEl = document.getElementById('calendar'); var calendar = new FullCalendar.Calendar(calendarEl, { initialView: 'dayGridMonth', dateClick: function(info) { // 현재 날짜를 가져옵니다. var today = new Date(); // 클릭한 날짜를 가져옵니다. var clickedDate = new Date(info.dateStr); // 명령어를 저장할 변수를 초기화합니다. var cmd = ''; // 클릭한 날짜와 현재 날짜를 비교합니다. if (clickedDate.toDateString() === today.toDateString()) { cmd = 'detailToday'; } else if (clickedDate < today) { cmd = 'detailBefore'; } else { cmd = 'detailAfter'; } // window.location.href를 사용하여 적절한 URL로 이동합니다. window.location.href = 'attendance.do?cmd=' + cmd + '&date=' + info.dateStr; } }); calendar.render(); });
- 출석부 설계
더보기- 시작 페이지인 main.js에는 full calendar 외부 라이브러리를 이용해서 월간 달력을 보여준다.
- 보고 싶은 출석부의 날짜를 선택
- 날짜가 오늘 이전이라면 이미 작성된 / 수정 불가능한 출석부 보여줌
- 날짜가 오늘 이후라면 출석부가 아직 작성되지 않았기 때문에 보여주지 않음
- 날짜가 오늘이라면 cmd=detailToday로 컨트롤러에 보내지고 DetailTodayAction.java 생성
- jsp에서 action으로 가져오는 데이터들은 date, classNo가 있고 session에서 kinderNo를 불러옴
- dao의 selectOneByAttendanceDate()가 1 이상이라면 출석부가 존재한다는 뜻.
- 0이라면 '출석부 생성' 버튼이 화면에 뜨고
- 1이라면 출석부가 이미 존재하기 때문에 '수정' 버튼이 뜬다.
- 출석부 생성을 누르면 cmd=insertAttendance가 controller로 넘어가고 AttendanceInsertAction 생성
- dao.selectAllByKinderNoAndClassNo를 불러와서 출석부 테이블 insert
만약 모달처럼 다른 페이지로 이동할 게 아니라면 jsp에서 controller -> action 방식으로 넘기지 말고 action 대신에 다른 servelet 파일 만들어서 값만 넣어도 됨
'LANGUAGE > Java, Spring' 카테고리의 다른 글
JSTL, EL 문법 정리 (1) 2024.12.03 Java Enum (0) 2024.12.03 Java의 정석 정리 (06장) (1) 2024.12.02 Java의 정석 정리 (05장) (2) 2024.12.02 Java의 정석 정리 (04장) (1) 2024.12.02