diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..0803e58 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/spring_basic2.iml b/.idea/spring_basic2.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/spring_basic2.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3838ede..45c5ce1 100644 --- a/README.md +++ b/README.md @@ -77,14 +77,14 @@

-4. Tomcat 9 설치 - https://tomcat.apache.org/download-90.cgi - [Windows] https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.50/bin/apache-tomcat-9.0.50-windows-x64.zip - [Mac] https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.50/bin/apache-tomcat-9.0.50.tar.gz +4. Tomcat 9 설치 - https://tomcat.apache.org/download-92.cgi + [Windows] https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.52/bin/apache-tomcat-9.0.52-windows-x64.zip + [Mac] https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.52/bin/apache-tomcat-9.0.52.tar.gz
다운로드 받은 파일을 설치하고자하는 디렉토리로 이동후 아래의 명령을 실행. 압축을 풀어서 사용자의 홈디렉토리(~)에 저장. ``` - $ tar -xvf apache-tomcat-9.0.50.tar.gz -C ~ + $ tar -xvf apache-tomcat-9.0.52.tar.gz -C ~ ``` **[참고]** 버전별 비교 - https://tomcat.apache.org/whichversion.html @@ -119,10 +119,14 @@ - **STS 3.9.17** **Windows** - https://download.springsource.com/release/STS/3.9.17.RELEASE/dist/e4.20/spring-tool-suite-3.9.17.RELEASE-e4.20.0-win32-x86_64.zip **MacOS** - https://download.springsource.com/release/STS/3.9.17.RELEASE/dist/e4.20/spring-tool-suite-3.9.17.RELEASE-e4.20.0-macosx-cocoa-x86_64.dmg +**MacOS M1** - https://www.jetbrains.com/idea/download/download-thanks.html?platform=macM1 +[참고] MocOS M1의 STS설치 및 설정 - https://codechobo.tistory.com/28 - **IntelliJ** **Windows** - https://www.jetbrains.com/idea/download/#section=windows **MacOS** - https://www.jetbrains.com/idea/download/#section=mac +**MacOS M1** - https://www.jetbrains.com/idea/download/download-thanks.html?platform=macM1 + [참고] IntelliJ 학생 라이센스 - https://www.jetbrains.com/shop/eform/students
diff --git a/ch2/BoardController.java b/ch2/BoardController.java new file mode 100644 index 0000000..cc91f0d --- /dev/null +++ b/ch2/BoardController.java @@ -0,0 +1,27 @@ +package com.fastcampus.ch2; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/board") +public class BoardController { + @GetMapping("/list") + public String list(HttpServletRequest request) { + if(!loginCheck(request)) + return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 + + return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 + } + + private boolean loginCheck(HttpServletRequest request) { + // 1. 세션을 얻어서 + HttpSession session = request.getSession(); + // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 + return session.getAttribute("id")!=null; + } +} diff --git a/ch2/DBConnectionTest2Test.java b/ch2/DBConnectionTest2Test.java new file mode 100644 index 0000000..0a82abf --- /dev/null +++ b/ch2/DBConnectionTest2Test.java @@ -0,0 +1,144 @@ +package com.fastcampus.ch3; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.sql.DataSource; +import javax.swing.tree.ExpandVetoException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Date; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) +public class DBConnectionTest2Test { + @Autowired + DataSource ds; + + @Test + public void insertUserTest() throws Exception { + User user = new User("asdf2", "1234", "abc", "aaaa@aaa.com", new Date(), "fb", new Date()); + deleteAll(); + int rowCnt = insertUser(user); + + assertTrue(rowCnt==1); + } + + @Test + public void selectUserTest() throws Exception { + deleteAll(); + User user = new User("asdf2", "1234", "abc", "aaaa@aaa.com", new Date(), "fb", new Date()); + int rowCnt = insertUser(user); + User user2 = selectUser("asdf2"); + + assertTrue(user.getId().equals("asdf2")); + } + + @Test + public void deleteUserTest() throws Exception { + deleteAll(); + int rowCnt = deleteUser("asdf"); + + assertTrue(rowCnt==0); + + User user = new User("asdf2", "1234", "abc", "aaaa@aaa.com", new Date(), "fb", new Date()); + rowCnt = insertUser(user); + assertTrue(rowCnt==1); + + rowCnt = deleteUser(user.getId()); + assertTrue(rowCnt==1); + + assertTrue(selectUser(user.getId())==null); + + } + + // 매개변수로 받은 사용자 정보로 user_info테이블을 update하는 메서드 + public int updateUser(User user) throws Exception { + return 0; + } + + public int deleteUser(String id) throws Exception { + Connection conn = ds.getConnection(); + + String sql = "delete from user_info where id= ? "; + + PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 + pstmt.setString(1, id); +// int rowCnt = pstmt.executeUpdate(); // insert, delete, update +// return rowCnt; + return pstmt.executeUpdate(); // insert, delete, update + } + + public User selectUser(String id) throws Exception { + Connection conn = ds.getConnection(); + + String sql = "select * from user_info where id= ? "; + + PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 + pstmt.setString(1,id); + ResultSet rs = pstmt.executeQuery(); // select + + if(rs.next()) { + User user = new User(); + user.setId(rs.getString(1)); + user.setPwd(rs.getString(2)); + user.setName(rs.getString(3)); + user.setEmail(rs.getString(4)); + user.setBirth(new Date(rs.getDate(5).getTime())); + user.setSns(rs.getString(6)); + user.setReg_date(new Date(rs.getTimestamp(7).getTime())); + return user; + } + return null; + } + + private void deleteAll() throws Exception { + Connection conn = ds.getConnection(); + + String sql = "delete from user_info "; + + PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 + pstmt.executeUpdate(); // insert, delete, update + } + + // 사용자 정보를 user_info테이블에 저장하는 메서드 + public int insertUser(User user) throws Exception { + Connection conn = ds.getConnection(); + +// insert into user_info (id, pwd, name, email, birth, sns, reg_date) +// values ('asdf22', '1234', 'smith', 'aaa@aaa.com', '2022-01-01', 'facebook', now()); + + String sql = "insert into user_info values (?, ?, ?, ?,?,?, now()) "; + + PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 + pstmt.setString(1, user.getId()); + pstmt.setString(2, user.getPwd()); + pstmt.setString(3, user.getName()); + pstmt.setString(4, user.getEmail()); + pstmt.setDate(5, new java.sql.Date(user.getBirth().getTime())); + pstmt.setString(6, user.getSns()); + + int rowCnt = pstmt.executeUpdate(); // insert, delete, update + + return rowCnt; + } + + @Test + public void springJdbcConnectionTest() throws Exception { +// ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml"); +// DataSource ds = ac.getBean(DataSource.class); + + Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다. + + System.out.println("conn = " + conn); + assertTrue(conn!=null); // 괄호 안의 조건식이 true면, 테스트 성공, 아니면 실패 + } +} diff --git a/ch2/ExceptionController.java b/ch2/ExceptionController.java new file mode 100644 index 0000000..95040ba --- /dev/null +++ b/ch2/ExceptionController.java @@ -0,0 +1,40 @@ +package com.fastcampus.ch2; + +import java.io.FileNotFoundException; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; + +@Controller +public class ExceptionController { + @ExceptionHandler({NullPointerException.class, FileNotFoundException.class}) + public String catcher2(Exception ex, Model m) { + m.addAttribute("ex", ex); + return "error"; + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 200 -> 500 + public String catcher(Exception ex, Model m) { + System.out.println("catcher() in ExceptionController"); + System.out.println("m="+m); +// m.addAttribute("ex", ex); + + return "error"; + } + + @RequestMapping("/ex") + public String main(Model m) throws Exception { + m.addAttribute("msg", "message from ExceptionController.main()"); + throw new Exception("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); + } + + @RequestMapping("/ex2") + public String main2() throws Exception { + throw new NullPointerException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); + } +} diff --git a/ch2/ExceptionController2.java b/ch2/ExceptionController2.java new file mode 100644 index 0000000..7c7aa55 --- /dev/null +++ b/ch2/ExceptionController2.java @@ -0,0 +1,31 @@ +package com.fastcampus.ch2; + +import java.io.FileNotFoundException; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; + +//@ResponseStatus(HttpStatus.BAD_REQUEST) // 500 -> 400 +class MyException extends RuntimeException { + MyException(String msg) { + super(msg); + } + MyException() { this(""); } +} + +@Controller +public class ExceptionController2 { + + @RequestMapping("/ex3") + public String main() throws Exception { + throw new MyException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); + } + + @RequestMapping("/ex4") + public String main2() throws Exception { + throw new FileNotFoundException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); + } +} + diff --git a/ch2/GlobalCatcher.java b/ch2/GlobalCatcher.java new file mode 100644 index 0000000..18e7044 --- /dev/null +++ b/ch2/GlobalCatcher.java @@ -0,0 +1,24 @@ +package com.fastcampus.ch2; + +import java.io.FileNotFoundException; + +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + + @ControllerAdvice("com.fastcampus.ch3") // ÁöÁ¤µÈ ÆÐŰÁö¿¡¼­ ¹ß»ýÇÑ ¿¹¿Ü¸¸ ó¸® +// @ControllerAdvice // ¸ðµç ÆÐŰÁö¿¡ Àû¿ë + public class GlobalCatcher { + @ExceptionHandler({NullPointerException.class, FileNotFoundException.class}) + public String catcher2(Exception ex, Model m) { + m.addAttribute("ex", ex); + return "error"; + } + + @ExceptionHandler(Exception.class) + public String catcher(Exception ex, Model m) { + m.addAttribute("ex", ex); + + return "error"; + } + } diff --git a/ch2/GlobalValidator.java b/ch2/GlobalValidator.java new file mode 100644 index 0000000..58107bc --- /dev/null +++ b/ch2/GlobalValidator.java @@ -0,0 +1,32 @@ +package com.fastcampus.ch2; + +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +public class GlobalValidator implements Validator { + @Override + public boolean supports(Class clazz) { +// return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인 + return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인 + } + + @Override + public void validate(Object target, Errors errors) { + System.out.println("GlobalValidator.validate() is called"); + + User user = (User)target; + + String id = user.getId(); + +// if(id==null || "".equals(id.trim())) { +// errors.rejectValue("id", "required"); +// } + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required"); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required"); + + if(id==null || id.length() < 5 || id.length() > 12) { + errors.rejectValue("id", "invalidLength", new String[]{"5", "12"}, null); + } + } +} diff --git a/ch2/RegisterController.java b/ch2/RegisterController.java index 4d9e7ef..5c3e303 100644 --- a/ch2/RegisterController.java +++ b/ch2/RegisterController.java @@ -16,7 +16,8 @@ public String register() { } // @RequestMapping(value="/register/save", method=RequestMethod.POST) // 신규회원 가입 - @PostMapping("/register/save") +// @PostMapping("/register/save") + @PostMapping("/register/add") public String save(@ModelAttribute("user") User user, Model m) { if(!isValid(user)) { String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8"); diff --git a/ch2/RequestParamTest.java b/ch2/RequestParamTest.java index c467688..4021cb5 100644 --- a/ch2/RequestParamTest.java +++ b/ch2/RequestParamTest.java @@ -91,7 +91,7 @@ public String main9(@RequestParam(required=true) int year) { @RequestMapping("/requestParam10") public String main10(@RequestParam(required=true, defaultValue="1") int year) { // http://localhost/ch2/requestParam10 ---->> year=1 - // http://localhost/ch2/requestParam10?year ---->> year=1 + // http://localhost/ch2/requestParam10?year ---->> 400 Bad Request, nested exception is java.lang.NumberFormatException: For input string: "" System.out.printf("[%s]year=[%s]%n", new Date(), year); return "yoil"; } @@ -99,7 +99,7 @@ public String main10(@RequestParam(required=true, defaultValue="1") int year) { @RequestMapping("/requestParam11") public String main11(@RequestParam(required=false, defaultValue="1") int year) { // http://localhost/ch2/requestParam11 ---->> year=1 -// http://localhost/ch2/requestParam11?year ---->> year=1 +// http://localhost/ch2/requestParam11?year ---->> 400 Bad Request, nested exception is java.lang.NumberFormatException: For input string: "" System.out.printf("[%s]year=[%s]%n", new Date(), year); return "yoil"; } diff --git a/ch2/UserValidator.java b/ch2/UserValidator.java new file mode 100644 index 0000000..a5c61f1 --- /dev/null +++ b/ch2/UserValidator.java @@ -0,0 +1,34 @@ +package com.fastcampus.ch2; + +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + + + public class UserValidator implements Validator { + @Override + public boolean supports(Class clazz) { +// return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인 + return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인 + } + + @Override + public void validate(Object target, Errors errors) { + System.out.println("LocalValidator.validate() is called"); + + User user = (User)target; + + String id = user.getId(); + + // if(id==null || "".equals(id.trim())) { + // errors.rejectValue("id", "required"); + // } + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required"); + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required"); + + if(id==null || id.length() < 5 || id.length() > 12) { + errors.rejectValue("id", "invalidLength"); + } + } + } + diff --git a/ch2/YoilTeller.java b/ch2/YoilTeller.java index cb82269..57af9f2 100644 --- a/ch2/YoilTeller.java +++ b/ch2/YoilTeller.java @@ -31,7 +31,7 @@ public void main(HttpServletRequest request, HttpServletResponse response) throw cal.set(yyyy, mm - 1, dd); int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); - char yoil = " 일월화수목금토".charAt(dayOfWeek); + char yoil = " 일월화수목금토".charAt(dayOfWeek); // 일요일:1, 월요일:2, ... // 3. 출력 // System.out.println(year + "년 " + month + "월 " + day + "일은 "); diff --git a/ch2/error_message.properties b/ch2/error_message.properties new file mode 100644 index 0000000..b198bc8 --- /dev/null +++ b/ch2/error_message.properties @@ -0,0 +1,3 @@ +required=필수 항목 입니다. +required.user.pwd=사용자 비밀번호는 필수 항목입니다. +invalidLength.id=아이디의 길이는 {0}~{1}사이어야 합니다. diff --git a/ch2/loginForm.jsp b/ch2/loginForm.jsp index db41d6d..0b0b31b 100644 --- a/ch2/loginForm.jsp +++ b/ch2/loginForm.jsp @@ -74,7 +74,7 @@ + + + diff --git a/ch3/menu.css b/ch3/menu.css new file mode 100644 index 0000000..dff59b7 --- /dev/null +++ b/ch3/menu.css @@ -0,0 +1,44 @@ +* { + box-sizing: border-box; + margin : 0; + padding: 0; +} + +a { text-decoration: none; } + +ul { + list-style-type: none; + height: 48px; + width: 100%; + background-color: #30426E; + display: flex; +} + +ul > li { + color: lightgray; + height : 100%; + width:90px; + display:flex; + align-items: center; +} + +ul > li > a { + color: lightgray; + margin:auto; + padding: 10px; + font-size:20px; + align-items: center; +} + +ul > li > a:hover { + color :white; + border-bottom: 3px solid rgb(209, 209, 209); +} + +#logo { + color:white; + font-size: 18px; + padding-left:40px; + margin-right:auto; + display: flex; +} diff --git a/ch3/registerForm.jsp b/ch3/registerForm.jsp new file mode 100644 index 0000000..2fdc20f --- /dev/null +++ b/ch3/registerForm.jsp @@ -0,0 +1,118 @@ +<%@ page contentType="text/html;charset=utf-8" %> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> + +<%@ page import="java.net.URLDecoder"%> + + + + + + + + + Register + + + + +
Register
+
+ + + + + + + + + + +
+ + + +
+ +
+ + + diff --git a/ch3/registerInfo.jsp b/ch3/registerInfo.jsp new file mode 100644 index 0000000..307b502 --- /dev/null +++ b/ch3/registerInfo.jsp @@ -0,0 +1,19 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8" + pageEncoding="UTF-8"%> + + + + +Insert title here + + +

id=${user.id}

+

pwd=${user.pwd}

+

name=${user.name}

+

email=${user.email}

+

birth=${user.birth}

+

hobby=${user.hobby}

+

sns=${user.sns}

+ + + diff --git a/ch3/root-context.xml b/ch3/root-context.xml new file mode 100644 index 0000000..bb31fa3 --- /dev/null +++ b/ch3/root-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ch3/root-context_aop.xml b/ch3/root-context_aop.xml new file mode 100644 index 0000000..600f26d --- /dev/null +++ b/ch3/root-context_aop.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/ch4/BoardController.java b/ch4/BoardController.java new file mode 100644 index 0000000..cdba4b1 --- /dev/null +++ b/ch4/BoardController.java @@ -0,0 +1,35 @@ +package com.fastcampus.ch4.controller; + +import com.fastcampus.ch4.domain.*; +import com.fastcampus.ch4.service.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; +import org.springframework.ui.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.*; + +import javax.servlet.http.*; +import java.time.*; +import java.util.*; + +@Controller +@RequestMapping("/board") +public class BoardController { + @Autowired + BoardService boardService; + + @GetMapping("/list") + public String list(HttpServletRequest request) { + if(!loginCheck(request)) + return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 + + return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 + } + + private boolean loginCheck(HttpServletRequest request) { + // 1. 세션을 얻어서 + HttpSession session = request.getSession(); + // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 + return session.getAttribute("id")!=null; + } +} diff --git a/ch4/BoardController2.java b/ch4/BoardController2.java new file mode 100644 index 0000000..797b89c --- /dev/null +++ b/ch4/BoardController2.java @@ -0,0 +1,151 @@ +package com.fastcampus.ch4.controller; + +import com.fastcampus.ch4.domain.*; +import com.fastcampus.ch4.service.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; +import org.springframework.ui.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.*; + +import javax.servlet.http.*; +import java.time.*; +import java.util.*; + +@Controller +@RequestMapping("/board") +public class BoardController { + @Autowired + BoardService boardService; + + @PostMapping("/modify") + public String modify(BoardDto boardDto, Integer page, Integer pageSize, RedirectAttributes rattr, Model m, HttpSession session) { + + String writer = (String)session.getAttribute("id"); + boardDto.setWriter(writer); + + try { + if (boardService.modify(boardDto)!= 1) + throw new Exception("Modify failed."); + + rattr.addAttribute("page", page); + rattr.addAttribute("pageSize", pageSize); + rattr.addFlashAttribute("msg", "MOD_OK"); + return "redirect:/board/list"; + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute(boardDto); + m.addAttribute("page", page); + m.addAttribute("pageSize", pageSize); + m.addAttribute("msg", "MOD_ERR"); + return "board"; // 등록하려던 내용을 보여줘야 함. + } + } + + @GetMapping("/write") + public String write(Model m) { + m.addAttribute("mode", "new"); + + return "board"; + } + + @PostMapping("/write") // insert니까 delete인 remove하고 동일 + public String write(BoardDto boardDto, RedirectAttributes rattr, Model m, HttpSession session) { + String writer = (String)session.getAttribute("id"); + boardDto.setWriter(writer); + + try { + if (boardService.write(boardDto) != 1) + throw new Exception("Write failed."); + + rattr.addFlashAttribute("msg", "WRT_OK"); + return "redirect:/board/list"; + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute("mode", "new"); // 글쓰기 모드로 + m.addAttribute(boardDto); // 등록하려던 내용을 보여줘야 함. + m.addAttribute("msg", "WRT_ERR"); + return "board"; + } + } + + @GetMapping("/read") + public String read(Integer bno, Integer page, Integer pageSize, RedirectAttributes rattr, Model m) { + try { + BoardDto boardDto = boardService.read(bno); + m.addAttribute(boardDto); + m.addAttribute("page", page); + m.addAttribute("pageSize", pageSize); + } catch (Exception e) { + e.printStackTrace(); + rattr.addAttribute("page", page); + rattr.addAttribute("pageSize", pageSize); + rattr.addFlashAttribute("msg", "READ_ERR"); + return "redirect:/board/list"; + } + + return "board"; + } + + @PostMapping("/remove") + public String remove(Integer bno, Integer page, Integer pageSize, RedirectAttributes rattr, HttpSession session) { + String writer = (String)session.getAttribute("id"); + String msg = "DEL_OK"; + + try { + if(boardService.remove(bno, writer)!=1) + throw new Exception("Delete failed."); + } catch (Exception e) { + e.printStackTrace(); + msg = "DEL_ERR"; + } + + rattr.addAttribute("page", page); + rattr.addAttribute("pageSize", pageSize); + rattr.addFlashAttribute("msg", msg); + return "redirect:/board/list"; + } + + @GetMapping("/list") + public String list(@RequestParam(defaultValue ="1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize,Model m, HttpServletRequest request) { + if(!loginCheck(request)) + return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 + + try { + int totalCnt = boardService.getCount(); + m.addAttribute("totalCnt", totalCnt); + + PageHandler pageHandler = new PageHandler(totalCnt, page, pageSize); + + if(page < 0 || page > pageHandler.getTotalPage()) + page = 1; + if(pageSize < 0 || pageSize > 50) + pageSize = 10; + + Map map = new HashMap(); + map.put("offset", (page-1)*pageSize); + map.put("pageSize", pageSize); + + List list = boardService.getPage(map); + m.addAttribute("list", list); + m.addAttribute("ph", pageHandler); + + Instant startOfToday = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant(); + m.addAttribute("startOfToday", startOfToday.toEpochMilli()); + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute("msg", "LIST_ERR"); + m.addAttribute("totalCnt", 0); + } + + return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 + } + + private boolean loginCheck(HttpServletRequest request) { + // 1. 세션을 얻어서(false는 session이 없어도 새로 생성하지 않는다. 반환값 null) + HttpSession session = request.getSession(false); + // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 + return session!=null && session.getAttribute("id")!=null; + } +} diff --git a/ch4/BoardController3.java b/ch4/BoardController3.java new file mode 100644 index 0000000..e0857b8 --- /dev/null +++ b/ch4/BoardController3.java @@ -0,0 +1,130 @@ +package com.fastcampus.ch4.controller; + +import com.fastcampus.ch4.domain.*; +import com.fastcampus.ch4.service.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; +import org.springframework.ui.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.mvc.support.*; + +import javax.servlet.http.*; +import java.time.*; +import java.util.*; + +@Controller +@RequestMapping("/board") +public class BoardController { + @Autowired + BoardService boardService; + + @PostMapping("/modify") + public String modify(BoardDto boardDto, SearchCondition sc, RedirectAttributes rattr, Model m, HttpSession session) { + String writer = (String)session.getAttribute("id"); + boardDto.setWriter(writer); + + try { + if (boardService.modify(boardDto)!= 1) + throw new Exception("Modify failed."); + + rattr.addFlashAttribute("msg", "MOD_OK"); + return "redirect:/board/list"+sc.getQueryString(); + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute(boardDto); + m.addAttribute("msg", "MOD_ERR"); + return "board"; + } + } + + @GetMapping("/write") + public String write(Model m) { + m.addAttribute("mode", "new"); + + return "board"; + } + + @PostMapping("/write") + public String write(BoardDto boardDto, RedirectAttributes rattr, Model m, HttpSession session) { + String writer = (String)session.getAttribute("id"); + boardDto.setWriter(writer); + + try { + if (boardService.write(boardDto) != 1) + throw new Exception("Write failed."); + + rattr.addFlashAttribute("msg", "WRT_OK"); + return "redirect:/board/list"; + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute(boardDto); + m.addAttribute("mode", "new"); + m.addAttribute("msg", "WRT_ERR"); + return "board"; + } + } + + @GetMapping("/read") + public String read(Integer bno, SearchCondition sc, RedirectAttributes rattr, Model m) { + try { + BoardDto boardDto = boardService.read(bno); + m.addAttribute(boardDto); + } catch (Exception e) { + e.printStackTrace(); + rattr.addFlashAttribute("msg", "READ_ERR"); + return "redirect:/board/list"+sc.getQueryString(); + } + + return "board"; + } + + @PostMapping("/remove") + public String remove(Integer bno, SearchCondition sc, RedirectAttributes rattr, HttpSession session) { + String writer = (String)session.getAttribute("id"); + String msg = "DEL_OK"; + + try { + if(boardService.remove(bno, writer)!=1) + throw new Exception("Delete failed."); + } catch (Exception e) { + e.printStackTrace(); + msg = "DEL_ERR"; + } + + rattr.addFlashAttribute("msg", msg); + return "redirect:/board/list"+sc.getQueryString(); + } + + @GetMapping("/list") + public String list(Model m, SearchCondition sc, HttpServletRequest request) { + if(!loginCheck(request)) + return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 + + try { + int totalCnt = boardService.getSearchResultCnt(sc); + m.addAttribute("totalCnt", totalCnt); + + PageHandler pageHandler = new PageHandler(totalCnt, sc); + + List list = boardService.getSearchResultPage(sc); + m.addAttribute("list", list); + m.addAttribute("ph", pageHandler); + + Instant startOfToday = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant(); + m.addAttribute("startOfToday", startOfToday.toEpochMilli()); + } catch (Exception e) { + e.printStackTrace(); + m.addAttribute("msg", "LIST_ERR"); + m.addAttribute("totalCnt", 0); + } + + return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 + } + + private boolean loginCheck(HttpServletRequest request) { + // 1. 세션을 얻어서(false는 session이 없어도 새로 생성하지 않는다. 반환값 null) + HttpSession session = request.getSession(false); + // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 + return session!=null && session.getAttribute("id")!=null; + } +} diff --git a/ch4/BoardDao.java b/ch4/BoardDao.java new file mode 100644 index 0000000..a3cd784 --- /dev/null +++ b/ch4/BoardDao.java @@ -0,0 +1,21 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; + +import java.util.*; + +public interface BoardDao { + BoardDto select(Integer bno) throws Exception; + int delete(Integer bno, String writer) throws Exception; + int insert(BoardDto dto) throws Exception; + int update(BoardDto dto) throws Exception; + int increaseViewCnt(Integer bno) throws Exception; + + List selectPage(Map map) throws Exception; + List selectAll() throws Exception; + int deleteAll() throws Exception; + int count() throws Exception; + + int searchResultCnt(SearchCondition sc) throws Exception; + List searchSelectPage(SearchCondition sc) throws Exception; +} diff --git a/ch4/BoardDaoImpl.java b/ch4/BoardDaoImpl.java new file mode 100644 index 0000000..e343841 --- /dev/null +++ b/ch4/BoardDaoImpl.java @@ -0,0 +1,72 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.apache.ibatis.session.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; + +import java.util.*; + +@Repository +public class BoardDaoImpl implements BoardDao { + @Autowired + private SqlSession session; + private static String namespace = "com.fastcampus.ch4.dao.BoardMapper."; + + public int count() throws Exception { + return session.selectOne(namespace+"count"); + } // T selectOne(String statement) + + @Override + public int deleteAll() { + return session.delete(namespace+"deleteAll"); + } // int delete(String statement) + + @Override + public int delete(Integer bno, String writer) throws Exception { + Map map = new HashMap(); + map.put("bno", bno); + map.put("writer", writer); + return session.delete(namespace+"delete", map); + } // int delete(String statement, Object parameter) + + public int insert(BoardDto dto) throws Exception { + return session.insert(namespace+"insert", dto); + } // int insert(String statement, Object parameter) + + @Override + public List selectAll() throws Exception { + return session.selectList(namespace+"selectAll"); + } // List selectList(String statement) + + public BoardDto select(Integer bno) throws Exception { + return session.selectOne(namespace + "select", bno); + } // T selectOne(String statement, Object parameter) + + @Override + public List selectPage(Map map) throws Exception { + return session.selectList(namespace+"selectPage", map); + } // List selectList(String statement, Object parameter) + + @Override + public int update(BoardDto dto) throws Exception { + return session.update(namespace+"update", dto); + } // int update(String statement, Object parameter) + + @Override + public int increaseViewCnt(Integer bno) throws Exception { + return session.update(namespace+"increaseViewCnt", bno); + } // int update(String statement, Object parameter) + + @Override + public int searchResultCnt(SearchCondition sc) throws Exception { + System.out.println("sc in searchResultCnt() = " + sc); + System.out.println("session = " + session); + return session.selectOne(namespace+"searchResultCnt", sc); + } // T selectOne(String statement, Object parameter) + + @Override + public List searchSelectPage(SearchCondition sc) throws Exception { + return session.selectList(namespace+"searchSelectPage", sc); + } // List selectList(String statement, Object parameter) +} diff --git a/ch4/BoardDaoImplTest.java b/ch4/BoardDaoImplTest.java new file mode 100644 index 0000000..ecba83b --- /dev/null +++ b/ch4/BoardDaoImplTest.java @@ -0,0 +1,196 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.junit.*; +import org.junit.runner.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.test.context.*; +import org.springframework.test.context.junit4.*; + +import java.util.*; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) +public class BoardDaoImplTest { + @Autowired + private BoardDao boardDao; + + @Test + public void countTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.count()==1); + + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.count()==2); + } + + @Test + public void deleteAllTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.deleteAll()==1); + assertTrue(boardDao.count()==0); + + boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.deleteAll()==2); + assertTrue(boardDao.count()==0); + } + + @Test + public void deleteTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + Integer bno = boardDao.selectAll().get(0).getBno(); + assertTrue(boardDao.delete(bno, boardDto.getWriter())==1); + assertTrue(boardDao.count()==0); + + assertTrue(boardDao.insert(boardDto)==1); + bno = boardDao.selectAll().get(0).getBno(); + assertTrue(boardDao.delete(bno, boardDto.getWriter()+"222")==0); + assertTrue(boardDao.count()==1); + + assertTrue(boardDao.delete(bno, boardDto.getWriter())==1); + assertTrue(boardDao.count()==0); + + assertTrue(boardDao.insert(boardDto)==1); + bno = boardDao.selectAll().get(0).getBno(); + assertTrue(boardDao.delete(bno+1, boardDto.getWriter())==0); + assertTrue(boardDao.count()==1); + } + + @Test + public void insertTest() throws Exception { + boardDao.deleteAll(); + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + + boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.count()==2); + + boardDao.deleteAll(); + boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.count()==1); + } + + @Test + public void selectAllTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + List list = boardDao.selectAll(); + assertTrue(list.size() == 0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + + list = boardDao.selectAll(); + assertTrue(list.size() == 1); + + assertTrue(boardDao.insert(boardDto)==1); + list = boardDao.selectAll(); + assertTrue(list.size() == 2); + } + + @Test + public void selectTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + + Integer bno = boardDao.selectAll().get(0).getBno(); + boardDto.setBno(bno); + BoardDto boardDto2 = boardDao.select(bno); + assertTrue(boardDto.equals(boardDto2)); + } + + @Test + public void selectPageTest() throws Exception { + boardDao.deleteAll(); + + for (int i = 1; i <= 10; i++) { + BoardDto boardDto = new BoardDto(""+i, "no content"+i, "asdf"); + boardDao.insert(boardDto); + } + + Map map = new HashMap(); + map.put("offset", 0); + map.put("pageSize", 3); + + List list = boardDao.selectPage(map); + assertTrue(list.get(0).getTitle().equals("10")); + assertTrue(list.get(1).getTitle().equals("9")); + assertTrue(list.get(2).getTitle().equals("8")); + + map = new HashMap(); + map.put("offset", 0); + map.put("pageSize", 1); + + list = boardDao.selectPage(map); + assertTrue(list.get(0).getTitle().equals("10")); + + map = new HashMap(); + map.put("offset", 7); + map.put("pageSize", 3); + + list = boardDao.selectPage(map); + assertTrue(list.get(0).getTitle().equals("3")); + assertTrue(list.get(1).getTitle().equals("2")); + assertTrue(list.get(2).getTitle().equals("1")); + } + + @Test + public void updateTest() throws Exception { + boardDao.deleteAll(); + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + + Integer bno = boardDao.selectAll().get(0).getBno(); + System.out.println("bno = " + bno); + boardDto.setBno(bno); + boardDto.setTitle("yes title"); + assertTrue(boardDao.update(boardDto)==1); + + BoardDto boardDto2 = boardDao.select(bno); + assertTrue(boardDto.equals(boardDto2)); + } + + @Test + public void increaseViewCntTest() throws Exception { + boardDao.deleteAll(); + assertTrue(boardDao.count()==0); + + BoardDto boardDto = new BoardDto("no title", "no content", "asdf"); + assertTrue(boardDao.insert(boardDto)==1); + assertTrue(boardDao.count()==1); + + Integer bno = boardDao.selectAll().get(0).getBno(); + assertTrue(boardDao.increaseViewCnt(bno)==1); + + boardDto = boardDao.select(bno); + assertTrue(boardDto!=null); + assertTrue(boardDto.getView_cnt() == 1); + + assertTrue(boardDao.increaseViewCnt(bno)==1); + boardDto = boardDao.select(bno); + assertTrue(boardDto!=null); + assertTrue(boardDto.getView_cnt() == 2); + } +} diff --git a/ch4/BoardDto.java b/ch4/BoardDto.java new file mode 100644 index 0000000..b16f7a6 --- /dev/null +++ b/ch4/BoardDto.java @@ -0,0 +1,89 @@ +package com.fastcampus.ch4.domain; + +import java.util.*; + +public class BoardDto { + private Integer bno; + private String title; + private String content; + private String writer; + private int view_cnt; + private int comment_cnt; + private Date reg_date; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + BoardDto boardDto = (BoardDto) o; + return Objects.equals(bno, boardDto.bno) && Objects.equals(title, boardDto.title) && Objects.equals(content, boardDto.content) && Objects.equals(writer, boardDto.writer); + } + + @Override + public int hashCode() { + return Objects.hash(bno, title, content, writer); + } + + public BoardDto() { this("","",""); } + public BoardDto(String title, String content, String writer){ + this.title = title; + this.content = content; + this.writer = writer; + } + + public Integer getBno() { + return bno; + } + public void setBno(Integer bno) { + this.bno = bno; + } + public String getTitle() { + return title; + } + public void setTitle(String title) { + this.title = title; + } + public String getContent() { + return content; + } + public void setContent(String content) { + this.content = content; + } + public String getWriter() { + return writer; + } + public void setWriter(String writer) { + this.writer = writer; + } + public int getView_cnt() { + return view_cnt; + } + public void setView_cnt(int view_cnt) { + this.view_cnt = view_cnt; + } + public int getComment_cnt() { + return comment_cnt; + } + public void setComment_cnt(int comment_cnt) { + this.comment_cnt = comment_cnt; + } + public Date getReg_date() { + return reg_date; + } + public void setReg_date(Date reg_date) { + this.reg_date = reg_date; + } + + @Override + public String toString() { + return "BoardDto{" + + "bno=" + bno + + ", title='" + title + '\'' + + ", content='" + content + '\'' + + ", writer='" + writer + '\'' + + ", view_cnt=" + view_cnt + + ", comment_cnt=" + comment_cnt + + ", reg_date=" + reg_date + + '}'; + } +} diff --git a/ch4/BoardService.java b/ch4/BoardService.java new file mode 100644 index 0000000..659b722 --- /dev/null +++ b/ch4/BoardService.java @@ -0,0 +1,18 @@ +package com.fastcampus.ch4.service; + +import com.fastcampus.ch4.domain.*; + +import java.util.*; + +public interface BoardService { + int getCount() throws Exception; + int remove(Integer bno, String writer) throws Exception; + int write(BoardDto boardDto) throws Exception; + List getList() throws Exception; + BoardDto read(Integer bno) throws Exception; + List getPage(Map map) throws Exception; + int modify(BoardDto boardDto) throws Exception; + + int getSearchResultCnt(SearchCondition sc) throws Exception; + List getSearchResultPage(SearchCondition sc) throws Exception; +} diff --git a/ch4/BoardServiceImpl.java b/ch4/BoardServiceImpl.java new file mode 100644 index 0000000..017f060 --- /dev/null +++ b/ch4/BoardServiceImpl.java @@ -0,0 +1,62 @@ +package com.fastcampus.ch4.service; + +import com.fastcampus.ch4.dao.*; +import com.fastcampus.ch4.domain.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; + +import java.util.*; + +@Service +public class BoardServiceImpl implements BoardService { + @Autowired + BoardDao boardDao; + + @Override + public int getCount() throws Exception { + return boardDao.count(); + } + + @Override + public int remove(Integer bno, String writer) throws Exception { + return boardDao.delete(bno, writer); + } + + @Override + public int write(BoardDto boardDto) throws Exception { + return boardDao.insert(boardDto); + } + + @Override + public List getList() throws Exception { + return boardDao.selectAll(); + } + + @Override + public BoardDto read(Integer bno) throws Exception { + BoardDto boardDto = boardDao.select(bno); + boardDao.increaseViewCnt(bno); + + return boardDto; + } + + @Override + public List getPage(Map map) throws Exception { + return boardDao.selectPage(map); + } + + @Override + public int modify(BoardDto boardDto) throws Exception { + return boardDao.update(boardDto); + } + + @Override + public int getSearchResultCnt(SearchCondition sc) throws Exception { + return boardDao.searchResultCnt(sc); + } + + @Override + public List getSearchResultPage(SearchCondition sc) throws Exception { + return boardDao.searchSelectPage(sc); + } +} diff --git a/ch4/BoardServiceImplTest.java b/ch4/BoardServiceImplTest.java new file mode 100644 index 0000000..854a9a0 --- /dev/null +++ b/ch4/BoardServiceImplTest.java @@ -0,0 +1,34 @@ +package com.fastcampus.ch4.service; + +import org.junit.*; + +import java.time.*; + +import static org.junit.Assert.*; + +public class BoardServiceImplTest { + + @Test + public void read() { + } + + @Test + public void edit() { + } + + @Test + public void write() { + } + + @Test + public void remove() { + } + + @Test + public void getPage() { + } + + @Test + public void getList() { + } +} diff --git a/ch4/CommentController.java b/ch4/CommentController.java new file mode 100644 index 0000000..633fcda --- /dev/null +++ b/ch4/CommentController.java @@ -0,0 +1,103 @@ +package com.fastcampus.ch4.controller; + +import com.fastcampus.ch4.domain.CommentDto; +import com.fastcampus.ch4.service.CommentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpSession; +import java.util.List; + +//@Controller +//@ResponseBody +@RestController +public class CommentController { + @Autowired + CommentService service; + +// { +// "pcno":0, +// "comment" : "hihihi", +// "commenter" : "asdf" +// } + // 댓글을 수정하는 메서드 + @PatchMapping("/comments/{cno}") // /ch4/comments/26 PATCH + public ResponseEntity modify(@PathVariable Integer cno, @RequestBody CommentDto dto) { +// String commenter = (String)session.getAttribute("id"); + String commenter = "asdf"; + dto.setCommenter(commenter); + dto.setCno(cno); + System.out.println("dto = " + dto); + + try { + if(service.modify(dto)!=1) + throw new Exception("Write failed."); + + return new ResponseEntity<>("MOD_OK", HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity("MOD_ERR", HttpStatus.BAD_REQUEST); + } + } + +// { +// "pcno":0, +// "comment" : "hi" +// } + // 댓글을 등록하는 메서드 + @PostMapping("/comments") // /ch4/comments?bno=1085 POST + public ResponseEntity write(@RequestBody CommentDto dto, Integer bno, HttpSession session) { +// String commenter = (String)session.getAttribute("id"); + String commenter = "asdf"; + dto.setCommenter(commenter); + dto.setBno(bno); + System.out.println("dto = " + dto); + + try { + if(service.write(dto)!=1) + throw new Exception("Write failed."); + + return new ResponseEntity<>("WRT_OK", HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity("WRT_ERR", HttpStatus.BAD_REQUEST); + } + } + + // 지정된 댓글을 삭제하는 메서드 + @DeleteMapping("/comments/{cno}") // DELETE /comments/1?bno=1085 <-- 삭제할 댓글 번호 + public ResponseEntity remove(@PathVariable Integer cno, Integer bno, HttpSession session) { +// String commenter = (String)session.getAttribute("id"); + String commenter = "asdf"; + + try { + int rowCnt = service.remove(cno, bno, commenter); + + if(rowCnt!=1) + throw new Exception("Delete Failed"); + + return new ResponseEntity<>("DEL_OK", HttpStatus.OK); + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity<>("DEL_ERR", HttpStatus.BAD_REQUEST); + } + } + + // 지정된 게시물의 모든 댓글을 가져오는 메서드 + @GetMapping("/comments") // /comments?bno=1080 GET + public ResponseEntity> list(Integer bno) { + List list = null; + try { + list = service.getList(bno); + return new ResponseEntity>(list, HttpStatus.OK); // 200 + } catch (Exception e) { + e.printStackTrace(); + return new ResponseEntity>(HttpStatus.BAD_REQUEST); // 400 + } + } + + +} diff --git a/ch4/CommentDao.java b/ch4/CommentDao.java new file mode 100644 index 0000000..50c2f8d --- /dev/null +++ b/ch4/CommentDao.java @@ -0,0 +1,16 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.CommentDto; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface CommentDao { + int count(Integer bno) throws Exception; + int deleteAll(Integer bno); + int delete(Integer cno, String commenter) throws Exception; + int insert(CommentDto dto) throws Exception; + List selectAll(Integer bno) throws Exception; + CommentDto select(Integer cno) throws Exception; + int update(CommentDto dto) throws Exception; +} diff --git a/ch4/CommentDaoImpl.java b/ch4/CommentDaoImpl.java new file mode 100644 index 0000000..872d501 --- /dev/null +++ b/ch4/CommentDaoImpl.java @@ -0,0 +1,54 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.apache.ibatis.annotations.*; +import org.apache.ibatis.session.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; + +import java.util.*; + +@Repository +public class CommentDaoImpl implements CommentDao { + @Autowired + private SqlSession session; + private static String namespace = "com.fastcampus.ch4.dao.CommentMapper."; + + @Override + public int count(Integer bno) throws Exception { + return session.selectOne(namespace+"count", bno); + } // T selectOne(String statement) + + @Override + public int deleteAll(Integer bno) { + return session.delete(namespace+"deleteAll", bno); + } // int delete(String statement) + + @Override + public int delete(Integer cno, String commenter) throws Exception { + Map map = new HashMap(); + map.put("cno", cno); + map.put("commenter", commenter); + return session.delete(namespace+"delete", map); + } // int delete(String statement, Object parameter) + + @Override + public int insert(CommentDto dto) throws Exception { + return session.insert(namespace+"insert", dto); + } // int insert(String statement, Object parameter) + + @Override + public List selectAll(Integer bno) throws Exception { + return session.selectList(namespace+"selectAll", bno); + } // List selectList(String statement) + + @Override + public CommentDto select(Integer cno) throws Exception { + return session.selectOne(namespace + "select", cno); + } // T selectOne(String statement, Object parameter) + + @Override + public int update(CommentDto dto) throws Exception { + return session.update(namespace+"update", dto); + } // int update(String statement, Object parameter) +} diff --git a/ch4/CommentDaoImplTest.java b/ch4/CommentDaoImplTest.java new file mode 100644 index 0000000..edb7c91 --- /dev/null +++ b/ch4/CommentDaoImplTest.java @@ -0,0 +1,96 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.junit.*; +import org.junit.runner.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.test.context.*; +import org.springframework.test.context.junit4.*; + +import java.util.*; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) +public class CommentDaoImplTest { + @Autowired + CommentDao commentDao; + + @Test + public void count() throws Exception { + commentDao.deleteAll(1); + assertTrue(commentDao.count(1)==0); + } + + @Test + public void delete() throws Exception { + commentDao.deleteAll(1); + CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==1); + } + + @Test + public void insert() throws Exception { + commentDao.deleteAll(1); + CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==1); + + commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==2); + } + + @Test + public void selectAll() throws Exception { + commentDao.deleteAll(1); + CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==1); + + List list = commentDao.selectAll(1); + assertTrue(list.size()==1); + + commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==2); + + list = commentDao.selectAll(1); + assertTrue(list.size()==2); + } + + @Test + public void select() throws Exception { + commentDao.deleteAll(1); + CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==1); + + List list = commentDao.selectAll(1); + String comment = list.get(0).getComment(); + String commenter = list.get(0).getCommenter(); + assertTrue(comment.equals(commentDto.getComment())); + assertTrue(commenter.equals(commentDto.getCommenter())); + } + + @Test + public void update() throws Exception { + commentDao.deleteAll(1); + CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); + assertTrue(commentDao.insert(commentDto)==1); + assertTrue(commentDao.count(1)==1); + + List list = commentDao.selectAll(1); + commentDto.setCno(list.get(0).getCno()); + commentDto.setComment("comment2"); + assertTrue(commentDao.update(commentDto)==1); + + list = commentDao.selectAll(1); + String comment = list.get(0).getComment(); + String commenter = list.get(0).getCommenter(); + assertTrue(comment.equals(commentDto.getComment())); + assertTrue(commenter.equals(commentDto.getCommenter())); + } +} diff --git a/ch4/CommentDto.java b/ch4/CommentDto.java new file mode 100644 index 0000000..38ee26e --- /dev/null +++ b/ch4/CommentDto.java @@ -0,0 +1,103 @@ +package com.fastcampus.ch4.domain; + +import java.util.*; + +public class CommentDto { + private Integer cno; + private Integer bno; + private Integer pcno; + private String comment; + private String commenter; + private Date reg_date; + private Date up_date; + + public CommentDto() {} + public CommentDto(Integer bno, Integer pcno, String comment, String commenter) { + this.bno = bno; + this.pcno = pcno; + this.comment = comment; + this.commenter = commenter; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CommentDto that = (CommentDto) o; + return Objects.equals(cno, that.cno) && Objects.equals(bno, that.bno) && Objects.equals(pcno, that.pcno) && Objects.equals(comment, that.comment) && Objects.equals(commenter, that.commenter); + } + + @Override + public int hashCode() { + return Objects.hash(cno, bno, pcno, comment, commenter); + } + + public Integer getBno() { + return bno; + } + + public void setBno(Integer bno) { + this.bno = bno; + } + + public Integer getPcno() { + return pcno; + } + + public void setPcno(Integer pcno) { + this.pcno = pcno; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getCommenter() { + return commenter; + } + + public void setCommenter(String commenter) { + this.commenter = commenter; + } + + public Date getReg_date() { + return reg_date; + } + + public void setReg_date(Date reg_date) { + this.reg_date = reg_date; + } + + public Date getUp_date() { + return up_date; + } + + public void setUp_date(Date up_date) { + this.up_date = up_date; + } + + public Integer getCno() { + return cno; + } + + public void setCno(Integer cno) { + this.cno = cno; + } + + @Override + public String toString() { + return "CommentDto{" + + "cno=" + cno + + ", bno=" + bno + + ", pcno=" + pcno + + ", comment='" + comment + '\'' + + ", commenter='" + commenter + '\'' + + ", reg_date=" + reg_date + + ", up_date=" + up_date + + '}'; + } +} diff --git a/ch4/CommentServiceImpl.java b/ch4/CommentServiceImpl.java new file mode 100644 index 0000000..cd6420e --- /dev/null +++ b/ch4/CommentServiceImpl.java @@ -0,0 +1,64 @@ +package com.fastcampus.ch4.service; + +import com.fastcampus.ch4.dao.*; +import com.fastcampus.ch4.domain.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.stereotype.*; +import org.springframework.transaction.annotation.*; + +import java.util.*; + +@Service +public class CommentServiceImpl implements CommentService { + @Autowired + BoardDao boardDao; + @Autowired + CommentDao commentDao; + +// @Autowired +// public CommentServiceImpl(CommentDao commentDao, BoardDao boardDao) { +// this.commentDao = commentDao; +// this.boardDao = boardDao; +// } + + @Override + public int getCount(Integer bno) throws Exception { + return commentDao.count(bno); + } + + @Override + + @Transactional(rollbackFor = Exception.class) + public int remove(Integer cno, Integer bno, String commenter) throws Exception { + int rowCnt = boardDao.updateCommentCnt(bno, -1); + System.out.println("updateCommentCnt - rowCnt = " + rowCnt); +// throw new Exception("test"); + rowCnt = commentDao.delete(cno, commenter); + System.out.println("rowCnt = " + rowCnt); + return rowCnt; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int write(CommentDto commentDto) throws Exception { + boardDao.updateCommentCnt(commentDto.getBno(), 1); +// throw new Exception("test"); + return commentDao.insert(commentDto); + } + + @Override + public List getList(Integer bno) throws Exception { +// throw new Exception("test"); + return commentDao.selectAll(bno); + } + + @Override + public CommentDto read(Integer cno) throws Exception { + return commentDao.select(cno); + } + + @Override + public int modify(CommentDto commentDto) throws Exception { + return commentDao.update(commentDto); + } +} diff --git a/ch4/CommentServiceImplTest.java b/ch4/CommentServiceImplTest.java new file mode 100644 index 0000000..fed2a55 --- /dev/null +++ b/ch4/CommentServiceImplTest.java @@ -0,0 +1,67 @@ +package com.fastcampus.ch4.service; + +import com.fastcampus.ch4.dao.*; +import com.fastcampus.ch4.domain.*; +import org.junit.*; +import org.junit.runner.*; +import org.springframework.beans.factory.annotation.*; +import org.springframework.test.context.*; +import org.springframework.test.context.junit4.*; + +import java.util.*; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) +public class CommentServiceImplTest { + @Autowired + CommentService commentService; + @Autowired + CommentDao commentDao; + @Autowired + BoardDao boardDao; + + @Test + public void remove() throws Exception { + boardDao.deleteAll(); + + BoardDto boardDto = new BoardDto("hello", "hello", "asdf"); + assertTrue(boardDao.insert(boardDto) == 1); + Integer bno = boardDao.selectAll().get(0).getBno(); + System.out.println("bno = " + bno); + + commentDao.deleteAll(bno); + CommentDto commentDto = new CommentDto(bno,0,"hi","qwer"); + + assertTrue(boardDao.select(bno).getComment_cnt() == 0); + assertTrue(commentService.write(commentDto)==1); + assertTrue(boardDao.select(bno).getComment_cnt() == 1); + + Integer cno = commentDao.selectAll(bno).get(0).getCno(); + + // 일부러 예외를 발생시키고 Tx가 취소되는지 확인해야. + int rowCnt = commentService.remove(cno, bno, commentDto.getCommenter()); + assertTrue(rowCnt==1); + assertTrue(boardDao.select(bno).getComment_cnt() == 0); + } + + @Test + public void write() throws Exception { + boardDao.deleteAll(); + + BoardDto boardDto = new BoardDto("hello", "hello", "asdf"); + assertTrue(boardDao.insert(boardDto) == 1); + Integer bno = boardDao.selectAll().get(0).getBno(); + System.out.println("bno = " + bno); + + commentDao.deleteAll(bno); + CommentDto commentDto = new CommentDto(bno,0,"hi","qwer"); + + assertTrue(boardDao.select(bno).getComment_cnt() == 0); + assertTrue(commentService.write(commentDto)==1); + + Integer cno = commentDao.selectAll(bno).get(0).getCno(); + assertTrue(boardDao.select(bno).getComment_cnt() == 1); + } +} diff --git a/ch4/LoginController.java b/ch4/LoginController.java new file mode 100644 index 0000000..d050dc2 --- /dev/null +++ b/ch4/LoginController.java @@ -0,0 +1,86 @@ +package com.fastcampus.ch4.controller; + +import java.net.URLEncoder; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import com.fastcampus.ch4.dao.*; +import com.fastcampus.ch4.domain.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.CookieValue; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/login") +public class LoginController { + @Autowired + UserDao userDao; + + @GetMapping("/login") + public String loginForm() { + return "loginForm"; + } + + @GetMapping("/logout") + public String logout(HttpSession session) { + // 1. 세션을 종료 + session.invalidate(); + // 2. 홈으로 이동 + return "redirect:/"; + } + + @PostMapping("/login") + public String login(String id, String pwd, String toURL, boolean rememberId, + HttpServletRequest request, HttpServletResponse response) throws Exception { + + // 1. id와 pwd를 확인 + if(!loginCheck(id, pwd)) { + // 2-1 일치하지 않으면, loginForm으로 이동 + String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", "utf-8"); + + return "redirect:/login/login?msg="+msg; + } + // 2-2. id와 pwd가 일치하면, + // 세션 객체를 얻어오기 + HttpSession session = request.getSession(); + // 세션 객체에 id를 저장 + session.setAttribute("id", id); + + if(rememberId) { + // 1. 쿠키를 생성 + Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import +// 2. 응답에 저장 + response.addCookie(cookie); + } else { + // 1. 쿠키를 삭제 + Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import + cookie.setMaxAge(0); // 쿠키를 삭제 +// 2. 응답에 저장 + response.addCookie(cookie); + } +// 3. 홈으로 이동 + toURL = toURL==null || toURL.equals("") ? "/" : toURL; + + return "redirect:"+toURL; + } + + private boolean loginCheck(String id, String pwd) { + User user = null; + + try { + user = userDao.selectUser(id); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + return user!=null && user.getPwd().equals(pwd); +// return "asdf".equals(id) && "1234".equals(pwd); + } +} diff --git a/ch4/PageHandler.java b/ch4/PageHandler.java new file mode 100644 index 0000000..866b3d5 --- /dev/null +++ b/ch4/PageHandler.java @@ -0,0 +1,141 @@ +package com.fastcampus.ch4.domain; + +import org.springframework.web.util.*; + +public class PageHandler { + private SearchCondition sc; +// private int pageSize = 10; // 한 페이지당 게시물 갯수 +// private int page; // 현재 페이지 +// private String option; +// private String keyword; + public final int NAV_SIZE = 10; // page navigation size + private int totalCnt; // 게시물의 총 갯수 + private int totalPage; // 전체 페이지의 갯수 + private int beginPage; // 화면에 보여줄 첫 페이지 + private int endPage; // 화면에 보여줄 마지막 페이지 + private boolean showNext = false; // 이후를 보여줄지의 여부. endPage==totalPage이면, showNext는 false + private boolean showPrev = false; // 이전을 보여줄지의 여부. beginPage==1이 아니면 showPrev는 false + + public PageHandler(int totalCnt, Integer page) { + this(totalCnt, new SearchCondition(page, 10)); + } + + public PageHandler(int totalCnt, Integer page, Integer pageSize) { + this(totalCnt, new SearchCondition(page, pageSize)); + } + + public PageHandler(int totalCnt, SearchCondition sc) { + this.totalCnt = totalCnt; + this.sc = sc; + + doPaging(totalCnt, sc); + } + + private void doPaging(int totalCnt, SearchCondition sc) { + this.totalPage = totalCnt / sc.getPageSize() + (totalCnt % sc.getPageSize()==0? 0:1); + this.sc.setPage(Math.min(sc.getPage(), totalPage)); // page가 totalPage보다 크지 않게 + this.beginPage = (this.sc.getPage() -1) / NAV_SIZE * NAV_SIZE + 1; // 11 -> 11, 10 -> 1, 15->11. 따로 떼어내서 테스트 + this.endPage = Math.min(beginPage + NAV_SIZE - 1, totalPage); + this.showPrev = beginPage!=1; + this.showNext = endPage!=totalPage; + } + + public String getQueryString() { + return getQueryString(this.sc.getPage()); + } + + public String getQueryString(Integer page) { + // ?page=10&pageSize=10&option=A&keyword=title + return UriComponentsBuilder.newInstance() + .queryParam("page", page) + .queryParam("pageSize", sc.getPageSize()) + .queryParam("option", sc.getOption()) + .queryParam("keyword", sc.getKeyword()) + .build().toString(); + } + + void print() { + System.out.println("page="+ sc.getPage()); + System.out.print(showPrev? "PREV " : ""); + + for(int i=beginPage;i<=endPage;i++) { + System.out.print(i+" "); + } + System.out.println(showNext? " NEXT" : ""); + } + + public SearchCondition getSc() { + return sc; + } + + public void setSc(SearchCondition sc) { + this.sc = sc; + } + + public int getTotalCnt() { + return totalCnt; + } + + public void setTotalCnt(int totalCnt) { + this.totalCnt = totalCnt; + } + + public boolean isShowNext() { + return showNext; + } + + public void setShowNext(boolean showNext) { + this.showNext = showNext; + } + + public int getBeginPage() { + return beginPage; + } + + public void setBeginPage(int beginPage) { + this.beginPage = beginPage; + } + + public int getNAV_SIZE() { + return NAV_SIZE; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getEndPage() { + return endPage; + } + + public void setEndPage(int endPage) { + this.endPage = endPage; + } + + public boolean isShowPrev() { + return showPrev; + } + + public void setShowPrev(boolean showPrev) { + this.showPrev = showPrev; + } + + @Override + public String toString() { + return "PageHandler{" + + "sc=" + sc + + ", totalCnt=" + totalCnt + + ", showNext=" + showNext + + ", beginPage=" + beginPage + + ", NAV_SIZE=" + NAV_SIZE + + ", totalPage=" + totalPage + + ", endPage=" + endPage + + ", showPrev=" + showPrev + + '}'; + } +} + diff --git a/ch4/SearchCondition.java b/ch4/SearchCondition.java new file mode 100644 index 0000000..ca7c7ef --- /dev/null +++ b/ch4/SearchCondition.java @@ -0,0 +1,93 @@ +package com.fastcampus.ch4.domain; + +import org.springframework.web.util.UriComponentsBuilder; + +import static java.lang.Math.*; +import static java.util.Objects.requireNonNullElse; + +public class SearchCondition { + private Integer page = 1; + private Integer pageSize = DEFAULT_PAGE_SIZE; + private String option = ""; + private String keyword = ""; +// private Integer offset; + + public static final int MIN_PAGE_SIZE = 5; + public static final int DEFAULT_PAGE_SIZE = 10; + public static final int MAX_PAGE_SIZE = 50; + + public SearchCondition(){} + + public SearchCondition(Integer page, Integer pageSize) { + this(page, pageSize, "", ""); + } + + public SearchCondition(Integer page, Integer pageSize, String option, String keyword) { + this.page = page; + this.pageSize = pageSize; + this.option = option; + this.keyword = keyword; + } + + public String getQueryString() { + return getQueryString(page); + } + + public String getQueryString(Integer page) { + // ?page=10&pageSize=10&option=A&keyword=title + return UriComponentsBuilder.newInstance() + .queryParam("page", page) + .queryParam("pageSize", pageSize) + .queryParam("option", option) + .queryParam("keyword", keyword) + .build().toString(); + } + public Integer getPage() { + return page; + } + + public void setPage(Integer page) { + this.page = page; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = requireNonNullElse(pageSize, DEFAULT_PAGE_SIZE); + + // MIN_PAGE_SIZE <= pageSize <= MAX_PAGE_SIZE + this.pageSize = max(MIN_PAGE_SIZE, min(this.pageSize, MAX_PAGE_SIZE)); + } + + public String getOption() { + return option; + } + + public void setOption(String option) { + this.option = option; + } + + public String getKeyword() { + return keyword; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public Integer getOffset() { + return (page-1)*pageSize; + } + + @Override + public String toString() { + return "SearchCondition{" + + "page=" + page + + ", pageSize=" + pageSize + + ", option='" + option + '\'' + + ", keyword='" + keyword + '\'' + + '}'; + } +} diff --git a/ch4/SimpleRestController.java b/ch4/SimpleRestController.java new file mode 100644 index 0000000..38c499c --- /dev/null +++ b/ch4/SimpleRestController.java @@ -0,0 +1,23 @@ +package com.fastcampus.ch4.controller; + +import com.fastcampus.ch4.domain.*; +import org.springframework.stereotype.*; +import org.springframework.web.bind.annotation.*; + +@Controller +public class SimpleRestController { + @GetMapping("/ajax") + public String ajax() { + return "ajax"; + } + + @PostMapping("/send") + @ResponseBody + public Person test(@RequestBody Person p) { + System.out.println("p = " + p); + p.setName("ABC"); + p.setAge(p.getAge() + 10); + + return p; + } +} diff --git a/ch4/User.java b/ch4/User.java new file mode 100644 index 0000000..327381f --- /dev/null +++ b/ch4/User.java @@ -0,0 +1,107 @@ +package com.fastcampus.ch4.domain; + +import java.util.Date; +import java.util.Objects; + +public class User { + private String id; + private String pwd; + private String name; + private String email; + private Date birth; + private String sns; + private Date reg_date; + + public User(){} + public User(String id, String pwd, String name, String email, Date birth, String sns, Date reg_date) { + this.id = id; + this.pwd = pwd; + this.name = name; + this.email = email; + this.birth = birth; + this.sns = sns; + this.reg_date = reg_date; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return id.equals(user.id) && Objects.equals(pwd, user.pwd) && Objects.equals(name, user.name) && Objects.equals(email, user.email) && Objects.equals(birth, user.birth) && Objects.equals(sns, user.sns); + } + + @Override + public int hashCode() { + return Objects.hash(id, pwd, name, email, birth, sns, reg_date); + } + + @Override + public String toString() { + return "User{" + + "id='" + id + '\'' + + ", pwd='" + pwd + '\'' + + ", name='" + name + '\'' + + ", email='" + email + '\'' + + ", birth=" + birth + + ", sns='" + sns + '\'' + + ", reg_date=" + reg_date + + '}'; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPwd() { + return pwd; + } + + public void setPwd(String pwd) { + this.pwd = pwd; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Date getBirth() { + return birth; + } + + public void setBirth(Date birth) { + this.birth = birth; + } + + public String getSns() { + return sns; + } + + public void setSns(String sns) { + this.sns = sns; + } + + public Date getReg_date() { + return reg_date; + } + + public void setReg_date(Date reg_date) { + this.reg_date = reg_date; + } +} diff --git a/ch4/UserDao.java b/ch4/UserDao.java new file mode 100644 index 0000000..736e88c --- /dev/null +++ b/ch4/UserDao.java @@ -0,0 +1,12 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; + +public interface UserDao { + User selectUser(String id) throws Exception; + int deleteUser(String id) throws Exception; + int insertUser(User user) throws Exception; + int updateUser(User user) throws Exception; + int count() throws Exception; + void deleteAll() throws Exception; +} diff --git a/ch4/UserDaoImpl.java b/ch4/UserDaoImpl.java new file mode 100644 index 0000000..27f1159 --- /dev/null +++ b/ch4/UserDaoImpl.java @@ -0,0 +1,136 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Date; + +@Repository +public class UserDaoImpl implements UserDao { + @Autowired + DataSource ds; + + @Override + public int deleteUser(String id) throws Exception { + int rowCnt = 0; + String sql = "DELETE FROM user_info WHERE id= ? "; + + try ( // try-with-resources - since jdk7 + Connection conn = ds.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); + ){ + pstmt.setString(1, id); + return pstmt.executeUpdate(); // insert, delete, update +// } catch (Exception e) { +// e.printStackTrace(); +// throw e; + } + } + + @Override + public User selectUser(String id) throws Exception { + User user = null; + String sql = "SELECT * FROM user_info WHERE id= ? "; + + try ( + Connection conn = ds.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); + ResultSet rs = pstmt.executeQuery(); // select + ){ + pstmt.setString(1, id); + + if (rs.next()) { + user = new User(); + user.setId(rs.getString(1)); + user.setPwd(rs.getString(2)); + user.setName(rs.getString(3)); + user.setEmail(rs.getString(4)); + user.setBirth(new Date(rs.getDate(5).getTime())); + user.setSns(rs.getString(6)); + user.setReg_date(new Date(rs.getTimestamp(7).getTime())); + } + } + + return user; + } + + // 사용자 정보를 user_info테이블에 저장하는 메서드 + @Override + public int insertUser(User user) throws Exception { + int rowCnt = 0; + String sql = "INSERT INTO user_info VALUES (?,?,?,?,?,?, now()) "; + + try( + Connection conn = ds.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 + ){ + pstmt.setString(1, user.getId()); + pstmt.setString(2, user.getPwd()); + pstmt.setString(3, user.getName()); + pstmt.setString(4, user.getEmail()); + pstmt.setDate(5, new java.sql.Date(user.getBirth().getTime())); + pstmt.setString(6, user.getSns()); + + return pstmt.executeUpdate(); + } + } + + @Override + public int updateUser(User user) throws Exception { + int rowCnt = 0; + + String sql = "UPDATE user_info " + + "SET pwd = ?, name=?, email=?, birth =?, sns=?, reg_date=? " + + "WHERE id = ? "; + + try ( + Connection conn = ds.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); + ){ + pstmt.setString(1, user.getPwd()); + pstmt.setString(2, user.getName()); + pstmt.setString(3, user.getEmail()); + pstmt.setDate(4, new java.sql.Date(user.getBirth().getTime())); + pstmt.setString(5, user.getSns()); + pstmt.setTimestamp(6, new java.sql.Timestamp(user.getReg_date().getTime())); + pstmt.setString(7, user.getId()); + + rowCnt = pstmt.executeUpdate(); + } + + return rowCnt; + } + + @Override + public int count() throws Exception { + String sql = "SELECT count(*) FROM user_info "; + + try( + Connection conn = ds.getConnection(); + PreparedStatement pstmt = conn.prepareStatement(sql); + ResultSet rs = pstmt.executeQuery(); + ){ + rs.next(); + int result = rs.getInt(1); + + return result; + } + } + + @Override + public void deleteAll() throws Exception { + try (Connection conn = ds.getConnection();) + { + String sql = "DELETE FROM user_info "; + PreparedStatement pstmt = conn.prepareStatement(sql); + pstmt.executeUpdate(); + } + } +} diff --git a/ch4/UserDaoImplTest.java b/ch4/UserDaoImplTest.java new file mode 100644 index 0000000..362dfc6 --- /dev/null +++ b/ch4/UserDaoImplTest.java @@ -0,0 +1,99 @@ +package com.fastcampus.ch4.dao; + +import com.fastcampus.ch4.domain.*; +import org.junit.*; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.Calendar; +import java.util.Date; + +import static org.junit.Assert.*; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) +public class UserDaoImplTest { + @Autowired + UserDao userDao; + Calendar cal; + + @Before // 각 테스트가 수행되기 직전에 이 메서드가 실행된다. + public void init() { + cal = Calendar.getInstance(); + cal.clear(); + cal.set(2021, 1, 1); + } + + @Test(expected = Exception.class) // 예외가 발생해야 테스트 통과 + public void insertUser() throws Exception { + userDao.deleteAll(); + assertTrue(userDao.count()==0); + + User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); + assertTrue(userDao.insertUser(user)==1); + assertTrue(userDao.count()==1); + + User user2 = userDao.selectUser(user.getId()); + assertTrue(user.equals(user2)); + + User user3 = new User("asdf222", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); + assertTrue(userDao.insertUser(user3)==1); + assertTrue(userDao.count()==2); + + // 같은 데이터를 2번 입력하고 예외가 발생하는지 테스트 + userDao.insertUser(user); // java.sql.SQLIntegrityConstraintViolationException예외발생. Duplicate entry 'asdf' for key 'PRIMARY' + } + + @Test + public void deleteUser() throws Exception { + userDao.deleteAll(); + assertTrue(userDao.count()==0); + + User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); + assertTrue(userDao.insertUser(user)==1); + assertTrue(userDao.count()==1); + + User user2 = userDao.selectUser(user.getId()); + assertTrue(user.equals(user2)); + assertTrue(userDao.deleteUser(user.getId())==1); + + user = userDao.selectUser("asdf"); + assertTrue(user==null); + assertTrue(userDao.count()==0); + } + + @Test + public void selectUser() throws Exception { + userDao.deleteAll(); + assertTrue(userDao.count()==0); + + User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); + assertTrue(userDao.insertUser(user)==1); + + User user2 = userDao.selectUser(user.getId()); + assertTrue(user.equals(user2)); + + user2 = userDao.selectUser("aaaaaaa"); + assertTrue(user2==null); + } + + @Test + public void updateUser() throws Exception { + userDao.deleteAll(); + User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); + int rowCnt = userDao.insertUser(user); + assertTrue(rowCnt==1); + + user.setPwd("4321"); + user.setEmail("bbb@bbb.com"); + rowCnt = userDao.updateUser(user); + assertTrue(rowCnt==1); + + User user2 = userDao.selectUser(user.getId()); + System.out.println("user = " + user); + System.out.println("user2 = " + user2); + assertTrue(user.equals(user2)); + } +} diff --git a/ch4/ajax.jsp b/ch4/ajax.jsp new file mode 100644 index 0000000..04cb4e0 --- /dev/null +++ b/ch4/ajax.jsp @@ -0,0 +1,37 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Title + + + +

{name:"abc", age:10}

+ +

Data From Server :

+
+ + + diff --git a/ch4/board.jsp b/ch4/board.jsp new file mode 100644 index 0000000..7afbb26 --- /dev/null +++ b/ch4/board.jsp @@ -0,0 +1,177 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> +<%@ page session="true"%> + + + + + + + + fastcampus + + + + + + + + +
+

게시판 ${mode=="new" ? "글쓰기" : "읽기"}

+
+ + +
+
+ + + + + + + + + + + + + +
+
+ + + diff --git a/ch4/board2.jsp b/ch4/board2.jsp new file mode 100644 index 0000000..6848130 --- /dev/null +++ b/ch4/board2.jsp @@ -0,0 +1,177 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> +<%@ page session="true"%> + + + + + + + + fastcampus + + + + + + + + +
+

게시판 ${mode=="new" ? "글쓰기" : "읽기"}

+
+ + +
+
+ + + + + + + + + + + + + +
+
+ + + diff --git a/ch4/board3.jsp b/ch4/board3.jsp new file mode 100644 index 0000000..bdc44e4 --- /dev/null +++ b/ch4/board3.jsp @@ -0,0 +1,176 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> +<%@ page session="true"%> + + + + + + + + fastcampus + + + + + + + + +
+

게시판 ${mode=="new" ? "글쓰기" : "읽기"}

+
+ + +
+
+ + + + + + + + + + + + +
+
+ + + diff --git a/ch4/boardList.jsp b/ch4/boardList.jsp new file mode 100644 index 0000000..5a01f3a --- /dev/null +++ b/ch4/boardList.jsp @@ -0,0 +1,29 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> + + + + + + fastcampus + + + +
+

This is BOARD

+

This is BOARD

+

This is BOARD

+

This is BOARD

+

This is BOARD

+
+ + diff --git a/ch4/boardList2.jsp b/ch4/boardList2.jsp new file mode 100644 index 0000000..172cfc8 --- /dev/null +++ b/ch4/boardList2.jsp @@ -0,0 +1,253 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> +<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %> +<%@ page session="true"%> + + + + + + + + fastcampus + + + + + + + + +
+
+
+
" class="search-form" method="get"> + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
번호제목이름등록일조회수
${boardDto.bno}">${boardDto.title}${boardDto.writer}${boardDto.view_cnt}
+
+
+
+ +
게시물이 없습니다.
+
+ + + ">< + + + ">${i} + + + ">> + + +
+
+
+
+ + diff --git a/ch4/boardList3.jsp b/ch4/boardList3.jsp new file mode 100644 index 0000000..129a42a --- /dev/null +++ b/ch4/boardList3.jsp @@ -0,0 +1,253 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %> +<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %> +<%@ page session="true"%> + + + + + + + + fastcampus + + + + + + + + +
+
+
+
" class="search-form" method="get"> + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
번호제목이름등록일조회수
${boardDto.bno}">${boardDto.title}${boardDto.writer}${boardDto.view_cnt}
+
+
+
+ +
게시물이 없습니다.
+
+ + + ">< + + + ">${i} + + + ">> + + +
+
+
+
+ + diff --git a/ch4/boardMapper.xml b/ch4/boardMapper.xml new file mode 100644 index 0000000..17533b6 --- /dev/null +++ b/ch4/boardMapper.xml @@ -0,0 +1,67 @@ + + + + + + + + DELETE FROM board + + + + DELETE FROM board WHERE bno = #{bno} and writer = #{writer} + + + + INSERT INTO board + (title, content, writer) + VALUES + (#{title}, #{content}, #{writer}) + + + + + + SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date + FROM board + + + + + + + + UPDATE board + SET title = #{title} + , content = #{content} + , up_date = now() + WHERE bno = #{bno} + + + + UPDATE board + SET comment_cnt = comment_cnt + #{cnt} + WHERE bno = #{bno} + + + + UPDATE board + SET view_cnt = view_cnt + 1 + WHERE bno = #{bno} + + + diff --git a/ch4/boardMapper2.xml b/ch4/boardMapper2.xml new file mode 100644 index 0000000..f941b34 --- /dev/null +++ b/ch4/boardMapper2.xml @@ -0,0 +1,97 @@ + + + + + + + + DELETE FROM board + + + + DELETE FROM board WHERE bno = #{bno} and writer = #{writer} + + + + INSERT INTO board + (title, content, writer) + VALUES + (#{title}, #{content}, #{writer}) + + + + + + SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date + FROM board + + + + + + + + UPDATE board + SET title = #{title} + , content = #{content} + , up_date = now() + WHERE bno = #{bno} + + + + UPDATE board + SET comment_cnt = comment_cnt + #{cnt} + WHERE bno = #{bno} + + + + UPDATE board + SET view_cnt = view_cnt + 1 + WHERE bno = #{bno} + + + + + + AND title LIKE concat('%', #{keyword}, '%') + + + AND writer LIKE concat('%', #{keyword}, '%') + + + AND (title LIKE concat('%', #{keyword}, '%') + OR content LIKE concat('%', #{keyword}, '%')) + + + + + + + + diff --git a/ch4/comment.html b/ch4/comment.html new file mode 100644 index 0000000..d7aa768 --- /dev/null +++ b/ch4/comment.html @@ -0,0 +1,393 @@ + + + + + + + + + Document + + + +
+
    +
  • + + + +
    +
    asdf
    +
    asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf +
    +
    + 2022.01.01 23:59:59 + 답글쓰기 + 수정 + 삭제 +
    +
    +
  • +
  • + + + +
    +
    qwer
    +
    qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer +
    +
    + 2022.01.01 23:59:59 + 답글쓰기 + 수정 + 삭제 +
    +
    +
  • +
+
+
+ < + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + > +
+
+
+
${id}
+
+ +
+
+
+ 등록 +
+
+
+
+
+
${id}
+
+ +
+
+
+ 등록 + 취소 +
+
+
+ + + + diff --git a/ch4/commentMapper.xml b/ch4/commentMapper.xml new file mode 100644 index 0000000..f7e894f --- /dev/null +++ b/ch4/commentMapper.xml @@ -0,0 +1,46 @@ + + + + + + DELETE FROM comment + WHERE bno = #{bno} + + + + + + DELETE FROM comment WHERE cno = #{cno} AND commenter = #{commenter} + + + + INSERT INTO comment + (bno, pcno, comment, commenter, reg_date, up_date) + VALUES + (#{bno}, #{pcno}, #{comment}, #{commenter}, now(), now()) + + + + + + + + UPDATE comment + SET comment = #{comment} + , up_date = now() + WHERE cno = #{cno} and commenter = #{commenter} + + diff --git a/ch4/create_table_board.sql b/ch4/create_table_board.sql new file mode 100644 index 0000000..ff35f34 --- /dev/null +++ b/ch4/create_table_board.sql @@ -0,0 +1,11 @@ +CREATE TABLE `board` ( +`bno` int(11) NOT NULL AUTO_INCREMENT, +`title` varchar(45) NOT NULL, +`content` text NOT NULL, +`writer` varchar(30) DEFAULT NULL, +`view_cnt` int(11) DEFAULT '0', +`comment_cnt` int(11) DEFAULT '0', +`reg_date` datetime DEFAULT CURRENT_TIMESTAMP, +`up_date` datetime DEFAULT CURRENT_TIMESTAMP, +PRIMARY KEY (`bno`) +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; diff --git a/ch4/index.jsp b/ch4/index.jsp new file mode 100644 index 0000000..190cb63 --- /dev/null +++ b/ch4/index.jsp @@ -0,0 +1,32 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ page session="false"%> + + + + + + + + fastcampus + + + + + +
+

This is HOME

+

This is HOME

+

This is HOME

+
+ + diff --git a/ch4/log4jdbc.log4j2.properties b/ch4/log4jdbc.log4j2.properties new file mode 100644 index 0000000..dec7e76 --- /dev/null +++ b/ch4/log4jdbc.log4j2.properties @@ -0,0 +1 @@ +log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator diff --git a/ch4/logback.xml b/ch4/logback.xml new file mode 100644 index 0000000..a588e89 --- /dev/null +++ b/ch4/logback.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/ch4/loginForm.jsp b/ch4/loginForm.jsp new file mode 100644 index 0000000..97a807b --- /dev/null +++ b/ch4/loginForm.jsp @@ -0,0 +1,110 @@ +<%@ page language="java" contentType="text/html; charset=UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> +<%@ page session="false"%> + + + + + + + + fastcampus + + + + + + +
" method="post" onsubmit="return formCheck(this);"> +

Login

+
+ + ${URLDecoder.decode(param.msg)} + +
+ + + + +
+ | + 비밀번호 찾기 | + 회원가입 +
+ +
+ + diff --git a/ch4/menu.css b/ch4/menu.css new file mode 100644 index 0000000..3084ed6 --- /dev/null +++ b/ch4/menu.css @@ -0,0 +1,44 @@ +* { + box-sizing: border-box; + margin : 0; + padding: 0; +} + +a { text-decoration: none; } + +ul { + list-style-type: none; + height: 48px; + width: 100%; + background-color: #30426E; + display: flex; +} + +ul > li { + color: lightgray; + height : 100%; + width:90px; + display:flex; + align-items: center; +} + +ul > li > a { + color: lightgray; + margin:auto; + padding: 10px; + font-size:20px; + align-items: center; +} + +ul > li > a:hover { + color :white; + border-bottom: 3px solid rgb(209, 209, 209); +} + +#logo { + color:white; + font-size: 18px; + padding-left:40px; + margin-right:auto; + display: flex; +} diff --git a/ch4/mybatis-config.xml b/ch4/mybatis-config.xml new file mode 100644 index 0000000..08aee59 --- /dev/null +++ b/ch4/mybatis-config.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/ch4/pom.xml b/ch4/pom.xml new file mode 100644 index 0000000..c63c080 --- /dev/null +++ b/ch4/pom.xml @@ -0,0 +1,211 @@ + + + 4.0.0 + com.fastcampus + ch4 + ch4 + war + 1.0.0-BUILD-SNAPSHOT + + 11 + 5.0.7.RELEASE + 1.6.10 + 1.6.6 + + + + + org.mybatis + mybatis + 3.5.9 + + + + org.mybatis + mybatis-spring + 2.0.7 + + + + + + org.springframework + spring-jdbc + ${org.springframework-version} + + + + + mysql + mysql-connector-java + 8.0.28 + + + + + com.google.guava + guava + 31.0.1-jre + + + + + org.springframework + spring-context + ${org.springframework-version} + + + + commons-logging + commons-logging + + + + + org.springframework + spring-webmvc + ${org.springframework-version} + + + + org.springframework + spring-aop + ${org.springframework-version} + + + + + org.aspectj + aspectjrt + ${org.aspectj-version} + + + + org.aspectj + aspectjweaver + 1.9.7 + + + + + + org.slf4j + slf4j-api + ${org.slf4j-version} + + + org.slf4j + jcl-over-slf4j + ${org.slf4j-version} + runtime + + + org.slf4j + slf4j-log4j12 + ${org.slf4j-version} + runtime + + + log4j + log4j + 1.2.15 + + + javax.mail + mail + + + javax.jms + jms + + + com.sun.jdmk + jmxtools + + + com.sun.jmx + jmxri + + + runtime + + + + + javax.inject + javax.inject + 1 + + + + + + javax.servlet + javax.servlet-api + 4.0.1 + provided + + + + + javax.servlet.jsp + javax.servlet.jsp-api + 2.3.3 + provided + + + + javax.servlet + jstl + 1.2 + + + + + javax.validation + validation-api + 2.0.1.Final + + + + + + org.springframework + spring-test + ${org.springframework-version} + test + + + + junit + junit + 4.12 + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + ${java-version} + ${java-version} + -Xlint:all + true + true + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + org.test.int1.Main + + + + + diff --git a/ch4/root-context.xml b/ch4/root-context.xml new file mode 100644 index 0000000..6eb3e0f --- /dev/null +++ b/ch4/root-context.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ch4/servlet-context.xml b/ch4/servlet-context.xml new file mode 100644 index 0000000..c884e97 --- /dev/null +++ b/ch4/servlet-context.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ch4/test.jsp b/ch4/test.jsp new file mode 100644 index 0000000..79f973d --- /dev/null +++ b/ch4/test.jsp @@ -0,0 +1,165 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + Title + + + +

commentTest

+comment:
+ + + +
+ + + + diff --git a/ch4/test2.jsp b/ch4/test2.jsp new file mode 100644 index 0000000..4ec26ba --- /dev/null +++ b/ch4/test2.jsp @@ -0,0 +1,505 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + + + + Document + + + +
+
+
${id}
+
+ +
+
+
+ 등록 +
+
+
+
+
+
+
+ < + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + > +
+
+
+
+
${id}
+
+ +
+
+
+ 등록 + 취소 +
+
+
+ + + + diff --git a/ch4/web.xml b/ch4/web.xml new file mode 100644 index 0000000..731ddd6 --- /dev/null +++ b/ch4/web.xml @@ -0,0 +1,51 @@ + + + + + + contextConfigLocation + /WEB-INF/spring/root-context.xml + + + + + org.springframework.web.context.ContextLoaderListener + + + + + appServlet + org.springframework.web.servlet.DispatcherServlet + + contextConfigLocation + /WEB-INF/spring/appServlet/servlet-context.xml + + 1 + + + + appServlet + / + + + + encodingFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + + + + encodingFilter + /* + + + diff --git a/ch5/readme.md b/ch5/readme.md index e69de29..9c558e3 100644 --- a/ch5/readme.md +++ b/ch5/readme.md @@ -0,0 +1 @@ +. diff --git a/ch5/springbasic.mwb b/ch5/springbasic.mwb new file mode 100644 index 0000000..f9ea79e Binary files /dev/null and b/ch5/springbasic.mwb differ diff --git "a/ch5/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" "b/ch5/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" new file mode 100644 index 0000000..a3906a0 Binary files /dev/null and "b/ch5/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" differ diff --git "a/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" new file mode 100644 index 0000000..13c70db Binary files /dev/null and "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" differ diff --git "a/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" new file mode 100644 index 0000000..95f436d Binary files /dev/null and "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" differ diff --git "a/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" new file mode 100644 index 0000000..2a19a1c Binary files /dev/null and "b/ch5/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" differ diff --git a/ch6/readme.md b/ch6/readme.md deleted file mode 100644 index e69de29..0000000 diff --git a/ch7/readme.md b/ch7/readme.md deleted file mode 100644 index 9c558e3..0000000 --- a/ch7/readme.md +++ /dev/null @@ -1 +0,0 @@ -. diff --git "a/download/MySQL57\354\204\244\354\271\230\353\260\251\353\262\225_MacOS_m1.md" "b/download/MySQL57\354\204\244\354\271\230\353\260\251\353\262\225_MacOS_m1.md" new file mode 100644 index 0000000..3875706 --- /dev/null +++ "b/download/MySQL57\354\204\244\354\271\230\353\260\251\353\262\225_MacOS_m1.md" @@ -0,0 +1,5 @@ +## MySQL8.x버전을 M1칩 Mac에 설치하는 방법 + +아래의 링크를 클릭하세요. + +https://codechobo.tistory.com/31 diff --git a/download/ch2_final_mac.zip b/download/ch2_final_mac.zip new file mode 100644 index 0000000..98103af Binary files /dev/null and b/download/ch2_final_mac.zip differ diff --git a/download/ch3_final.zip b/download/ch3_final.zip new file mode 100644 index 0000000..a2e03c5 Binary files /dev/null and b/download/ch3_final.zip differ diff --git a/download/ch4.zip b/download/ch4.zip new file mode 100644 index 0000000..78d143f Binary files /dev/null and b/download/ch4.zip differ diff --git a/download/myportfolio.zip b/download/myportfolio.zip new file mode 100644 index 0000000..1cf7ffa Binary files /dev/null and b/download/myportfolio.zip differ diff --git "a/download/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" "b/download/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" new file mode 100644 index 0000000..a3906a0 Binary files /dev/null and "b/download/\341\204\221\341\205\263\341\204\205\341\205\251\341\204\214\341\205\246\341\206\250\341\204\220\341\205\263_\341\204\221\341\205\241\341\204\213\341\205\265\341\206\257\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250.xlsx" differ diff --git "a/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" new file mode 100644 index 0000000..13c70db Binary files /dev/null and "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257.pptx" differ diff --git "a/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" new file mode 100644 index 0000000..95f436d Binary files /dev/null and "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\211\341\205\242\341\206\267\341\204\221\341\205\263\341\206\257_\341\204\214\341\205\256\341\204\214\341\205\256\341\204\206\341\205\241\341\204\217\341\205\246\341\206\272.pdf" differ diff --git "a/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" new file mode 100644 index 0000000..2a19a1c Binary files /dev/null and "b/download/\341\204\222\341\205\252\341\204\206\341\205\247\341\206\253\341\204\214\341\205\245\341\206\274\341\204\213\341\205\264\341\204\211\341\205\245_\341\204\213\341\205\255\341\204\211\341\205\251.pptx" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_13_DispatcherServlet.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_13_DispatcherServlet.pdf" new file mode 100644 index 0000000..a952e46 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_13_DispatcherServlet.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_14_\341\204\203\341\205\246\341\204\213\341\205\265\341\204\220\341\205\245\341\204\213\341\205\264\341\204\207\341\205\247\341\206\253\341\204\222\341\205\252\341\206\253\341\204\200\341\205\252\341\204\200\341\205\245\341\206\267\341\204\214\341\205\263\341\206\274.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_14_\341\204\203\341\205\246\341\204\213\341\205\265\341\204\220\341\205\245\341\204\213\341\205\264\341\204\207\341\205\247\341\206\253\341\204\222\341\205\252\341\206\253\341\204\200\341\205\252\341\204\200\341\205\245\341\206\267\341\204\214\341\205\263\341\206\274.pdf" new file mode 100644 index 0000000..2a9e8d1 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch2_14_\341\204\203\341\205\246\341\204\213\341\205\265\341\204\220\341\205\245\341\204\213\341\205\264\341\204\207\341\205\247\341\206\253\341\204\222\341\205\252\341\206\253\341\204\200\341\205\252\341\204\200\341\205\245\341\206\267\341\204\214\341\205\263\341\206\274.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_1_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\262\341\206\274\341\204\202\341\205\242\341\204\202\341\205\242\341\204\200\341\205\2651.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_1_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\262\341\206\274\341\204\202\341\205\242\341\204\202\341\205\242\341\204\200\341\205\2651.pdf" new file mode 100644 index 0000000..9955e9f Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_1_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\262\341\206\274\341\204\202\341\205\242\341\204\202\341\205\242\341\204\200\341\205\2651.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_2_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265_\341\204\213\341\205\265\341\204\205\341\205\251\341\206\2531.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_2_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265_\341\204\213\341\205\265\341\204\205\341\205\251\341\206\2531.pdf" new file mode 100644 index 0000000..be067e6 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_2_\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274DI_\341\204\222\341\205\252\341\206\257\341\204\213\341\205\255\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265_\341\204\213\341\205\265\341\204\205\341\205\251\341\206\2531.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_3_DAO\341\204\213\341\205\264\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\200\341\205\252\341\204\214\341\205\245\341\206\250\341\204\213\341\205\255\341\206\274.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_3_DAO\341\204\213\341\205\264\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\200\341\205\252\341\204\214\341\205\245\341\206\250\341\204\213\341\205\255\341\206\274.pdf" new file mode 100644 index 0000000..997419e Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_3_DAO\341\204\213\341\205\264\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\200\341\205\252\341\204\214\341\205\245\341\206\250\341\204\213\341\205\255\341\206\274.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_4_Transaction_commit_rollback.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_4_Transaction_commit_rollback.pdf" new file mode 100644 index 0000000..5379335 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_4_Transaction_commit_rollback.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_5_AOP\341\204\213\341\205\264\341\204\200\341\205\242\341\204\202\341\205\247\341\206\267\341\204\200\341\205\252\341\204\213\341\205\255\341\206\274\341\204\213\341\205\245.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_5_AOP\341\204\213\341\205\264\341\204\200\341\205\242\341\204\202\341\205\247\341\206\267\341\204\200\341\205\252\341\204\213\341\205\255\341\206\274\341\204\213\341\205\245.pdf" new file mode 100644 index 0000000..5d46c5b Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_5_AOP\341\204\213\341\205\264\341\204\200\341\205\242\341\204\202\341\205\247\341\206\267\341\204\200\341\205\252\341\204\213\341\205\255\341\206\274\341\204\213\341\205\245.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_6_\341\204\211\341\205\245\341\204\207\341\205\265\341\204\211\341\205\263\341\204\200\341\205\250\341\204\216\341\205\263\341\206\274\341\204\213\341\205\264\341\204\207\341\205\256\341\206\253\341\204\205\341\205\265\341\204\213\341\205\252Transactional.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_6_\341\204\211\341\205\245\341\204\207\341\205\265\341\204\211\341\205\263\341\204\200\341\205\250\341\204\216\341\205\263\341\206\274\341\204\213\341\205\264\341\204\207\341\205\256\341\206\253\341\204\205\341\205\265\341\204\213\341\205\252Transactional.pdf" new file mode 100644 index 0000000..8bdd95f Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch3_6_\341\204\211\341\205\245\341\204\207\341\205\265\341\204\211\341\205\263\341\204\200\341\205\250\341\204\216\341\205\263\341\206\274\341\204\213\341\205\264\341\204\207\341\205\256\341\206\253\341\204\205\341\205\265\341\204\213\341\205\252Transactional.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_01_MyBatis\341\204\213\341\205\264\341\204\200\341\205\242\341\204\213\341\205\255\341\204\213\341\205\252\341\204\211\341\205\245\341\206\257\341\204\214\341\205\245\341\206\274.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_01_MyBatis\341\204\213\341\205\264\341\204\200\341\205\242\341\204\213\341\205\255\341\204\213\341\205\252\341\204\211\341\205\245\341\206\257\341\204\214\341\205\245\341\206\274.pdf" new file mode 100644 index 0000000..38d0927 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_01_MyBatis\341\204\213\341\205\264\341\204\200\341\205\242\341\204\213\341\205\255\341\204\213\341\205\252\341\204\211\341\205\245\341\206\257\341\204\214\341\205\245\341\206\274.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_02_MyBatis\341\204\205\341\205\251DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_02_MyBatis\341\204\205\341\205\251DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265.pdf" new file mode 100644 index 0000000..04236f4 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_02_MyBatis\341\204\205\341\205\251DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274\341\204\222\341\205\241\341\204\200\341\205\265.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_03_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250\341\204\206\341\205\241\341\206\253\341\204\203\341\205\263\341\206\257\341\204\200\341\205\265\341\204\213\341\205\252\341\204\221\341\205\246\341\204\213\341\205\265\341\204\214\341\205\265\341\206\274TDD.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_03_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250\341\204\206\341\205\241\341\206\253\341\204\203\341\205\263\341\206\257\341\204\200\341\205\265\341\204\213\341\205\252\341\204\221\341\205\246\341\204\213\341\205\265\341\204\214\341\205\265\341\206\274TDD.pdf" new file mode 100644 index 0000000..229a6a0 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_03_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\206\341\205\251\341\206\250\341\204\205\341\205\251\341\206\250\341\204\206\341\205\241\341\206\253\341\204\203\341\205\263\341\206\257\341\204\200\341\205\265\341\204\213\341\205\252\341\204\221\341\205\246\341\204\213\341\205\265\341\204\214\341\205\265\341\206\274TDD.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_04_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253CRUD\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_04_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253CRUD\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531.pdf" new file mode 100644 index 0000000..66f0bf9 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_04_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253CRUD\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_05_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\200\341\205\245\341\206\267\341\204\211\341\205\242\341\206\250\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\216\341\205\256\341\204\200\341\205\241.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_05_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\200\341\205\245\341\206\267\341\204\211\341\205\242\341\206\250\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\216\341\205\256\341\204\200\341\205\241.pdf" new file mode 100644 index 0000000..1f55862 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_05_\341\204\200\341\205\246\341\204\211\341\205\265\341\204\221\341\205\241\341\206\253\341\204\200\341\205\245\341\206\267\341\204\211\341\205\242\341\206\250\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\216\341\205\256\341\204\200\341\205\241.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_06_REST_API\341\204\213\341\205\252Ajax.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_06_REST_API\341\204\213\341\205\252Ajax.pdf" new file mode 100644 index 0000000..ffa582f Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_06_REST_API\341\204\213\341\205\252Ajax.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_07_\341\204\203\341\205\242\341\206\272\341\204\200\341\205\263\341\206\257\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531_DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_07_\341\204\203\341\205\242\341\206\272\341\204\200\341\205\263\341\206\257\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531_DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274.pdf" new file mode 100644 index 0000000..a344aac Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch4_07_\341\204\203\341\205\242\341\206\272\341\204\200\341\205\263\341\206\257\341\204\200\341\205\265\341\204\202\341\205\263\341\206\274\341\204\200\341\205\256\341\204\222\341\205\247\341\206\2531_DAO\341\204\214\341\205\241\341\206\250\341\204\211\341\205\245\341\206\274.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_01_02_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2651.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_01_02_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2651.pdf" new file mode 100644 index 0000000..cae73e7 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_01_02_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2651.pdf" differ diff --git "a/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_03_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2652.pdf" "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_03_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2652.pdf" new file mode 100644 index 0000000..7ededa1 Binary files /dev/null and "b/download/\352\260\225\354\235\230\354\236\220\353\243\214/[\341\204\211\341\205\263\341\204\221\341\205\263\341\204\205\341\205\265\341\206\274\341\204\213\341\205\264\341\204\214\341\205\245\341\206\274\341\204\211\341\205\245\341\206\250_\341\204\200\341\205\265\341\204\216\341\205\251\341\204\221\341\205\247\341\206\253]ch5_03_git\341\204\213\341\205\264\341\204\200\341\205\265\341\204\207\341\205\251\341\206\253\341\204\206\341\205\247\341\206\274\341\204\205\341\205\247\341\206\274\341\204\213\341\205\245\341\204\213\341\205\252\341\204\213\341\205\257\341\206\253\341\204\205\341\205\2652.pdf" differ diff --git "a/download/\354\235\270\355\205\224\353\246\254\354\240\234\354\235\264_\353\213\250\354\266\225\355\202\244.md" "b/download/\354\235\270\355\205\224\353\246\254\354\240\234\354\235\264_\353\213\250\354\266\225\355\202\244.md" new file mode 100644 index 0000000..06f352e --- /dev/null +++ "b/download/\354\235\270\355\205\224\353\246\254\354\240\234\354\235\264_\353\213\250\354\266\225\355\202\244.md" @@ -0,0 +1 @@ +# 인텔리제이 단축키 목록