├── .gitignore ├── .idea ├── .gitignore ├── modules.xml ├── spring_basic2.iml └── vcs.xml ├── LICENSE ├── README.md ├── ch2 ├── BoardController.java ├── Car.java ├── DBConnectionTest2Test.java ├── ExceptionController.java ├── ExceptionController2.java ├── GlobalCatcher.java ├── GlobalValidator.java ├── HelloServlet.java ├── LoginController.java ├── MethodCall.java ├── MethodCall2.java ├── MethodCall3.java ├── MethodInfo.java ├── MyDate.java ├── MyDispatcherServlet.java ├── PerformanceFilter.java ├── Person.java ├── PrivateMethodCall.java ├── RegisterController.java ├── RequestHeader.java ├── RequestInfo.java ├── RequestMappingTest.java ├── RequestMessage.java ├── RequestParamTest.java ├── SetterCall.java ├── TwoDice.java ├── TwoDiceServlet.java ├── User.java ├── UserValidator.java ├── YoilTeller.java ├── YoilTellerMVC.java ├── YoilTellerMVC2.java ├── YoilTellerMVC3.java ├── YoilTellerMVC4.java ├── YoilTellerMVC5.java ├── YoilTellerMVC6.java ├── YoilTellerServlet.java ├── boardList.jsp ├── dice.zip ├── el.jsp ├── error.jsp ├── error_message.properties ├── index.jsp ├── jstl.jsp ├── loginForm.jsp ├── menu.css ├── registerForm.html ├── registerForm.jsp ├── registerInfo.jsp ├── servlet-context.xml ├── twoDice.jsp ├── web.xml ├── yoil.jsp ├── yoilError.jsp └── yoilTeller.jsp ├── ch3 ├── AopMain.java ├── ApplicationContextTest.java ├── DBConnectionTest.java ├── DBConnectionTest2.java ├── DBConnectionTest2Test.java ├── DBConnectionTest3.java ├── HomeController.java ├── LoginController.java ├── RegisterController.java ├── User.java ├── UserDao.java ├── UserDaoImpl.java ├── UserValidator.java ├── config.xml ├── config1.xml ├── error_message.properties ├── index.jsp ├── loginForm.jsp ├── menu.css ├── readme.md ├── registerForm.jsp ├── registerInfo.jsp ├── root-context.xml └── root-context_aop.xml ├── ch4 ├── BoardController.java ├── BoardController2.java ├── BoardController3.java ├── BoardDao.java ├── BoardDaoImpl.java ├── BoardDaoImplTest.java ├── BoardDto.java ├── BoardService.java ├── BoardServiceImpl.java ├── BoardServiceImplTest.java ├── CommentController.java ├── CommentDao.java ├── CommentDaoImpl.java ├── CommentDaoImplTest.java ├── CommentDto.java ├── CommentServiceImpl.java ├── CommentServiceImplTest.java ├── LoginController.java ├── PageHandler.java ├── SearchCondition.java ├── SimpleRestController.java ├── User.java ├── UserDao.java ├── UserDaoImpl.java ├── UserDaoImplTest.java ├── ajax.jsp ├── board.jsp ├── board2.jsp ├── board3.jsp ├── boardList.jsp ├── boardList2.jsp ├── boardList3.jsp ├── boardMapper.xml ├── boardMapper2.xml ├── comment.html ├── commentMapper.xml ├── create_table_board.sql ├── index.jsp ├── log4jdbc.log4j2.properties ├── logback.xml ├── loginForm.jsp ├── menu.css ├── mybatis-config.xml ├── pom.xml ├── readme.md ├── root-context.xml ├── servlet-context.xml ├── test.jsp ├── test2.jsp └── web.xml ├── ch5 ├── readme.md ├── springbasic.mwb ├── 프로젝트_파일목록.xlsx ├── 화면정의서_샘플.pptx ├── 화면정의서_샘플_주주마켓.pdf └── 화면정의서_요소.pptx └── download ├── MySQL57설치방법_MacOS_m1.md ├── ch2.zip ├── ch2_final.zip ├── ch2_final_mac.zip ├── ch3.zip ├── ch3_final.zip ├── ch4.zip ├── firstSpring.zip ├── myportfolio.zip ├── project_import1.PNG ├── project_import2.PNG ├── readme.md ├── 프로젝트_파일목록.xlsx ├── 화면정의서_샘플.pptx ├── 화면정의서_샘플_주주마켓.pdf ├── 화면정의서_요소.pptx ├── 강의자료 ├── [스프링의정석_기초편]ch2_01_원격실행.pdf ├── [스프링의정석_기초편]ch2_02_HTTP요청과응답_실습.pdf ├── [스프링의정석_기초편]ch2_03_HTTP클라이언트서버.pdf ├── [스프링의정석_기초편]ch2_04_HTTP요청과응답_이론.pdf ├── [스프링의정석_기초편]ch2_05_SpringMVC.pdf ├── [스프링의정석_기초편]ch2_06_Servlet_JSP.pdf ├── [스프링의정석_기초편]ch2_07_RequestParam_ModelAttribute.pdf ├── [스프링의정석_기초편]ch2_08_redirect와forward.pdf ├── [스프링의정석_기초편]ch2_09_RequestMapping.pdf ├── [스프링의정석_기초편]ch2_10_쿠키.pdf ├── [스프링의정석_기초편]ch2_11_세션.pdf ├── [스프링의정석_기초편]ch2_12_예외처리.pdf ├── [스프링의정석_기초편]ch2_13_DispatcherServlet.pdf ├── [스프링의정석_기초편]ch2_14_데이터의변환과검증.pdf ├── [스프링의정석_기초편]ch3_1_스프링DI_흉내내기1.pdf ├── [스프링의정석_기초편]ch3_2_스프링DI_활용하기_이론1.pdf ├── [스프링의정석_기초편]ch3_3_DAO의작성과적용.pdf ├── [스프링의정석_기초편]ch3_4_Transaction_commit_rollback.pdf ├── [스프링의정석_기초편]ch3_5_AOP의개념과용어.pdf ├── [스프링의정석_기초편]ch3_6_서비스계층의분리와Transactional.pdf ├── [스프링의정석_기초편]ch4_01_MyBatis의개요와설정.pdf ├── [스프링의정석_기초편]ch4_02_MyBatis로DAO작성하기.pdf ├── [스프링의정석_기초편]ch4_03_게시판목록만들기와페이징TDD.pdf ├── [스프링의정석_기초편]ch4_04_게시판CRUD기능구현1.pdf ├── [스프링의정석_기초편]ch4_05_게시판검색기능추가.pdf ├── [스프링의정석_기초편]ch4_06_REST_API와Ajax.pdf ├── [스프링의정석_기초편]ch4_07_댓글기능구현1_DAO작성.pdf ├── [스프링의정석_기초편]ch5_01_02_git의기본명령어와원리1.pdf ├── [스프링의정석_기초편]ch5_03_git의기본명령어와원리2.pdf └── readme.md └── 인텔리제이_단축키.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/spring_basic2.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | No Cmmercial use, No Modification 2 | Distribution without modification and private use are allowed. 3 | 4 | Copyright (c) 2021 SEONG NAMKUNG 5 | 6 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 7 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 8 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 9 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 10 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 11 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 12 | SOFTWARE. 13 | -------------------------------------------------------------------------------- /ch2/BoardController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpSession; 5 | 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | @Controller 11 | @RequestMapping("/board") 12 | public class BoardController { 13 | @GetMapping("/list") 14 | public String list(HttpServletRequest request) { 15 | if(!loginCheck(request)) 16 | return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 17 | 18 | return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 19 | } 20 | 21 | private boolean loginCheck(HttpServletRequest request) { 22 | // 1. 세션을 얻어서 23 | HttpSession session = request.getSession(); 24 | // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 25 | return session.getAttribute("id")!=null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch2/Car.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | public class Car { 4 | private String color = "red"; 5 | public String getColor() { return color; } 6 | } 7 | 8 | -------------------------------------------------------------------------------- /ch2/ExceptionController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.FileNotFoundException; 4 | 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | 12 | @Controller 13 | public class ExceptionController { 14 | @ExceptionHandler({NullPointerException.class, FileNotFoundException.class}) 15 | public String catcher2(Exception ex, Model m) { 16 | m.addAttribute("ex", ex); 17 | return "error"; 18 | } 19 | 20 | @ExceptionHandler(Exception.class) 21 | @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 200 -> 500 22 | public String catcher(Exception ex, Model m) { 23 | System.out.println("catcher() in ExceptionController"); 24 | System.out.println("m="+m); 25 | // m.addAttribute("ex", ex); 26 | 27 | return "error"; 28 | } 29 | 30 | @RequestMapping("/ex") 31 | public String main(Model m) throws Exception { 32 | m.addAttribute("msg", "message from ExceptionController.main()"); 33 | throw new Exception("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); 34 | } 35 | 36 | @RequestMapping("/ex2") 37 | public String main2() throws Exception { 38 | throw new NullPointerException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ch2/ExceptionController2.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.FileNotFoundException; 4 | 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | 10 | //@ResponseStatus(HttpStatus.BAD_REQUEST) // 500 -> 400 11 | class MyException extends RuntimeException { 12 | MyException(String msg) { 13 | super(msg); 14 | } 15 | MyException() { this(""); } 16 | } 17 | 18 | @Controller 19 | public class ExceptionController2 { 20 | 21 | @RequestMapping("/ex3") 22 | public String main() throws Exception { 23 | throw new MyException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); 24 | } 25 | 26 | @RequestMapping("/ex4") 27 | public String main2() throws Exception { 28 | throw new FileNotFoundException("¿¹¿Ü°¡ ¹ß»ýÇß½À´Ï´Ù."); 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /ch2/GlobalCatcher.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.FileNotFoundException; 4 | 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @ControllerAdvice("com.fastcampus.ch3") // ÁöÁ¤µÈ ÆÐŰÁö¿¡¼­ ¹ß»ýÇÑ ¿¹¿Ü¸¸ ó¸® 10 | // @ControllerAdvice // ¸ðµç ÆÐŰÁö¿¡ Àû¿ë 11 | public class GlobalCatcher { 12 | @ExceptionHandler({NullPointerException.class, FileNotFoundException.class}) 13 | public String catcher2(Exception ex, Model m) { 14 | m.addAttribute("ex", ex); 15 | return "error"; 16 | } 17 | 18 | @ExceptionHandler(Exception.class) 19 | public String catcher(Exception ex, Model m) { 20 | m.addAttribute("ex", ex); 21 | 22 | return "error"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ch2/GlobalValidator.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.validation.Errors; 4 | import org.springframework.validation.ValidationUtils; 5 | import org.springframework.validation.Validator; 6 | 7 | public class GlobalValidator implements Validator { 8 | @Override 9 | public boolean supports(Class clazz) { 10 | // return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인 11 | return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인 12 | } 13 | 14 | @Override 15 | public void validate(Object target, Errors errors) { 16 | System.out.println("GlobalValidator.validate() is called"); 17 | 18 | User user = (User)target; 19 | 20 | String id = user.getId(); 21 | 22 | // if(id==null || "".equals(id.trim())) { 23 | // errors.rejectValue("id", "required"); 24 | // } 25 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required"); 26 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required"); 27 | 28 | if(id==null || id.length() < 5 || id.length() > 12) { 29 | errors.rejectValue("id", "invalidLength", new String[]{"5", "12"}, null); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch2/HelloServlet.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | 6 | import javax.servlet.ServletConfig; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.annotation.WebServlet; 9 | import javax.servlet.http.HttpServlet; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | //@WebServlet(urlPatterns={"/hello"}, loadOnStartup=1) 14 | @WebServlet("/hello") 15 | public class HelloServlet extends HttpServlet { 16 | @Override 17 | public void init() throws ServletException { 18 | // 서블릿 초기화 - 서블릿이 생성 또는 리로딩 때, 단 한번만 수행됨. 19 | System.out.println("[HelloSerlvet] init()"); 20 | } 21 | 22 | @Override // 호출될 때마다 반복적으로 수행됨. 23 | public void service(HttpServletRequest request, HttpServletResponse response) { 24 | // 1. 입력 25 | // 2. 처리 26 | // 3. 출력 27 | System.out.println("[HelloSerlvet] service()"); 28 | } 29 | 30 | @Override 31 | public void destroy() { 32 | // 뒷정리 작업 - 서블릿이 제거(unload)될 때, 단 한번만 수행됨. 33 | System.out.println("[HelloSerlvet] destroy()"); 34 | } 35 | } 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ch2/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.net.URLEncoder; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | 13 | @Controller 14 | @RequestMapping("/login") 15 | public class LoginController { 16 | @GetMapping("/login") 17 | public String loginForm() { 18 | return "loginForm"; 19 | } 20 | 21 | @PostMapping("/login") 22 | public String login(String id, String pwd, boolean rememberId, HttpServletResponse response) throws Exception { 23 | System.out.println("id="+id); 24 | System.out.println("pwd="+pwd); 25 | System.out.println("rememberId="+rememberId); 26 | // 1. id와 pwd를 확인 27 | if(!loginCheck(id, pwd)) { 28 | // 2-1 일치하지 않으면, loginForm으로 이동 29 | String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", "utf-8"); 30 | 31 | return "redirect:/login/login?msg="+msg; 32 | } 33 | 34 | // 2-2. id와 pwd가 일치하면, 35 | if(rememberId) { 36 | // 1. 쿠키를 생성 37 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 38 | // 2. 응답에 저장 39 | response.addCookie(cookie); 40 | } else { 41 | // 1. 쿠키를 삭제 42 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 43 | cookie.setMaxAge(0); // 쿠키를 삭제 44 | // 2. 응답에 저장 45 | response.addCookie(cookie); 46 | } 47 | // 3. 홈으로 이동 48 | return "redirect:/"; 49 | } 50 | 51 | private boolean loginCheck(String id, String pwd) { 52 | return "asdf".equals(id) && "1234".equals(pwd); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ch2/MethodCall.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.Scanner; 8 | import java.util.Set; 9 | 10 | public class MethodCall { 11 | public static void main(String[] args) throws Exception{ 12 | HashMap map = new HashMap(); 13 | System.out.println("before:"+map); 14 | 15 | ModelController mc = new ModelController(); 16 | String viewName = mc.main(map); 17 | 18 | System.out.println("after :"+map); 19 | 20 | render(map, viewName); 21 | } 22 | 23 | static void render(HashMap map, String viewName) throws IOException { 24 | String result = ""; 25 | 26 | // 1. 뷰의 내용을 한줄씩 읽어서 하나의 문자열로 만든다. 27 | Scanner sc = new Scanner(new File(viewName+".txt")); 28 | 29 | while(sc.hasNextLine()) 30 | result += sc.nextLine()+ System.lineSeparator(); 31 | 32 | // 2. map에 담긴 key를 하나씩 읽어서 template의 ${key}를 value바꾼다. 33 | Iterator it = map.keySet().iterator(); 34 | 35 | while(it.hasNext()) { 36 | String key = (String)it.next(); 37 | 38 | // 3. replace()로 key를 value 치환한다. 39 | result = result.replace("${"+key+"}", (String)map.get(key)); 40 | } 41 | 42 | // 4.렌더링 결과를 출력한다. 43 | System.out.println(result); 44 | } 45 | } 46 | 47 | class ModelController { 48 | public String main(HashMap map) { 49 | map.put("id", "asdf"); 50 | map.put("pwd", "1111"); 51 | 52 | return "txtView2"; 53 | } 54 | } 55 | 56 | [txtView1.txt] 57 | id=${id}, pwd=${pwd} 58 | 59 | [txtView2.txt] 60 | id:${id} 61 | pwd:${pwd} 62 | 63 | 64 | 65 | [실행결과] 66 | before:{} 67 | after :{id=asdf, pwd=1111} 68 | [txtView2.txt] 69 | id:asdf 70 | pwd:1111 71 | 72 | -------------------------------------------------------------------------------- /ch2/MethodCall2.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.lang.reflect.Method; 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | import java.util.Scanner; 9 | 10 | import org.springframework.ui.Model; 11 | import org.springframework.validation.support.BindingAwareModelMap; 12 | 13 | public class MethodCall2 { 14 | public static void main(String[] args) throws Exception{ 15 | 16 | Class clazz = Class.forName("com.fastcampus.ch2.YoilTellerMVC"); 17 | Object obj = clazz.newInstance(); 18 | 19 | Method main = clazz.getDeclaredMethod("main", int.class, int.class, int.class, Model.class); 20 | 21 | Model model = new BindingAwareModelMap(); 22 | System.out.println("[before] model="+model); 23 | 24 | // String viewName = obj.main(2021, 10, 1, model); 25 | String viewName = (String)main.invoke(obj, new Object[] { 2021, 10, 1, model }); 26 | System.out.println("viewName="+viewName); 27 | 28 | // Model의 내용을 출력 29 | System.out.println("[after] model="+model); 30 | 31 | // 텍스트 파일을 이용한 rendering 32 | render(model, viewName); 33 | } // main 34 | 35 | static void render(Model model, String viewName) throws IOException { 36 | String result = ""; 37 | 38 | // 1. 뷰의 내용을 한줄씩 읽어서 하나의 문자열로 만든다. 39 | Scanner sc = new Scanner(new File("src/main/webapp/WEB-INF/views/"+viewName+".jsp"), "utf-8"); 40 | 41 | while(sc.hasNextLine()) 42 | result += sc.nextLine()+ System.lineSeparator(); 43 | 44 | // 2. model을 map으로 변환 45 | Map map = model.asMap(); 46 | 47 | // 3.key를 하나씩 읽어서 template의 ${key}를 value바꾼다. 48 | Iterator it = map.keySet().iterator(); 49 | 50 | while(it.hasNext()) { 51 | String key = (String)it.next(); 52 | 53 | // 4. replace()로 key를 value 치환한다. 54 | result = result.replace("${"+key+"}", ""+map.get(key)); 55 | } 56 | 57 | // 5.렌더링 결과를 출력한다. 58 | System.out.println(result); 59 | } 60 | } 61 | 62 | /* [실행결과] 63 | [before] model={} 64 | viewName=yoil 65 | [after] model={year=2021, month=10, day=1, yoil=금} 66 | <%@ page contentType="text/html;charset=utf-8" %> 67 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 68 | <%@ page session="false" %> 69 | 70 | 71 | YoilTellerMVC 72 | 73 | 74 |

2021년 10월 1일은 금요일입니다.

75 | 76 | 77 | 78 | */ 79 | -------------------------------------------------------------------------------- /ch2/MethodCall3.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.lang.reflect.Method; 6 | import java.lang.reflect.Parameter; 7 | import java.util.Arrays; 8 | import java.util.HashMap; 9 | import java.util.Iterator; 10 | import java.util.Map; 11 | import java.util.Scanner; 12 | 13 | import org.springframework.ui.Model; 14 | import org.springframework.validation.support.BindingAwareModelMap; 15 | 16 | public class MethodCall3 { 17 | public static void main(String[] args) throws Exception{ 18 | Map map = new HashMap(); 19 | map.put("year", "2021"); 20 | map.put("month", "10"); 21 | map.put("day", "1"); 22 | 23 | Model model = null; 24 | Class clazz = Class.forName("com.fastcampus.ch2.YoilTellerMVC"); 25 | Object obj = clazz.newInstance(); 26 | 27 | // YoilTellerMVC.main(int year, int month, int day, Model model) 28 | Method main = clazz.getDeclaredMethod("main", int.class, int.class, int.class, Model.class); 29 | 30 | Parameter[] paramArr = main.getParameters(); 31 | Object[] argArr = new Object[main.getParameterCount()]; 32 | 33 | for(int i=0;i 108 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 109 | <%@ page session="false" %> 110 | 111 | 112 | YoilTellerMVC 113 | 114 | 115 |

2021년 10월 1일은 금요일입니다.

116 | 117 | 118 | */ 119 | -------------------------------------------------------------------------------- /ch2/MethodInfo.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.lang.reflect.Method; 4 | import java.lang.reflect.Parameter; 5 | import java.util.StringJoiner; 6 | 7 | public class MethodInfo { 8 | public static void main(String[] args) throws Exception{ 9 | 10 | Class clazz = Class.forName("com.fastcampus.ch2.YoilTeller"); 11 | Object obj = clazz.newInstance(); 12 | 13 | Method[] methodArr = clazz.getDeclaredMethods(); 14 | 15 | for(Method m : methodArr) { 16 | String name = m.getName(); 17 | Parameter[] paramArr = m.getParameters(); 18 | // Class[] paramTypeArr = m.getParameterTypes(); 19 | Class returnType = m.getReturnType(); 20 | 21 | StringJoiner paramList = new StringJoiner(", ", "(", ")"); 22 | 23 | for(Parameter param : paramArr) { 24 | String paramName = param.getName(); 25 | Class paramType = param.getType(); 26 | 27 | paramList.add(paramType.getName() + " " + paramName); 28 | } 29 | 30 | System.out.printf("%s %s%s%n", returnType.getName(), name, paramList); 31 | } 32 | } // main 33 | } 34 | 35 | /* [실행결과] 36 | java.lang.String main(java.lang.String year, java.lang.String month, java.lang.String day, org.springframework.ui.Model model) 37 | boolean isValid(int year, int month, int day) 38 | */ 39 | 40 | 41 | -------------------------------------------------------------------------------- /ch2/MyDate.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | public class MyDate { 4 | private int year; 5 | private int month; 6 | private int day; 7 | 8 | public int getYear() { 9 | return year; 10 | } 11 | 12 | public void setYear(int year) { 13 | this.year = year; 14 | } 15 | 16 | public int getMonth() { 17 | return month; 18 | } 19 | 20 | public void setMonth(int month) { 21 | this.month = month; 22 | } 23 | 24 | public int getDay() { 25 | return day; 26 | } 27 | 28 | public void setDay(int day) { 29 | this.day = day; 30 | } 31 | 32 | @Override 33 | public String toString() { 34 | return String.format("[year=%d, month=%d, day=%d]", year, month, day); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ch2/MyDispatcherServlet.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.PrintWriter; 6 | import java.lang.reflect.Array; 7 | import java.lang.reflect.Method; 8 | import java.lang.reflect.Parameter; 9 | import java.util.Arrays; 10 | import java.util.Iterator; 11 | import java.util.Map; 12 | import java.util.Scanner; 13 | 14 | import javax.servlet.annotation.WebServlet; 15 | import javax.servlet.http.HttpServlet; 16 | import javax.servlet.http.HttpServletRequest; 17 | import javax.servlet.http.HttpServletResponse; 18 | 19 | import org.springframework.ui.Model; 20 | import org.springframework.validation.support.BindingAwareModelMap; 21 | 22 | @WebServlet("/myDispatcherServlet") // http://localhost/ch2/myDispatcherServlet?year=2021&month=10&day=1 23 | public class MyDispatcherServlet extends HttpServlet { 24 | @Override 25 | public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 26 | Map map = request.getParameterMap(); 27 | Model model = null; 28 | String viewName = ""; 29 | 30 | try { 31 | Class clazz = Class.forName("com.fastcampus.ch2.YoilTellerMVC"); 32 | Object obj = clazz.newInstance(); 33 | 34 | // 1. main메서드의 정보를 얻는다. 35 | Method main = clazz.getDeclaredMethod("main", int.class, int.class, int.class, Model.class); 36 | 37 | // 2. main메서드의 매개변수 목록(paramArr)을 읽어서 메서드 호출에 사용할 인자 목록(argArr)을 만든다. 38 | Parameter[] paramArr = main.getParameters(); 39 | Object[] argArr = new Object[main.getParameterCount()]; 40 | 41 | for(int i=0;i int 76 | return Integer.valueOf((String)value); 77 | } else if(String.class.isInstance(value) && type==double.class) { // String -> double 78 | return Double.valueOf((String)value); 79 | } 80 | 81 | return value; 82 | } 83 | 84 | private String getResolvedViewName(String viewName) { 85 | return getServletContext().getRealPath("/WEB-INF/views") +"/"+viewName+".jsp"; 86 | } 87 | 88 | private void render(Model model, String viewName, HttpServletResponse response) throws IOException { 89 | String result = ""; 90 | 91 | response.setContentType("text/html"); 92 | response.setCharacterEncoding("utf-8"); 93 | PrintWriter out = response.getWriter(); 94 | 95 | // 1. 뷰의 내용을 한줄씩 읽어서 하나의 문자열로 만든다. 96 | Scanner sc = new Scanner(new File(getResolvedViewName(viewName)), "utf-8"); 97 | 98 | while(sc.hasNextLine()) 99 | result += sc.nextLine()+ System.lineSeparator(); 100 | 101 | // 2. model을 map으로 변환 102 | Map map = model.asMap(); 103 | 104 | // 3.key를 하나씩 읽어서 template의 ${key}를 value바꾼다. 105 | Iterator it = map.keySet().iterator(); 106 | 107 | while(it.hasNext()) { 108 | String key = (String)it.next(); 109 | 110 | // 4. replace()로 key를 value 치환한다. 111 | result = result.replace("${"+key+"}", map.get(key)+""); 112 | } 113 | 114 | // 5.렌더링 결과를 출력한다. 115 | out.println(result); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ch2/PerformanceFilter.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.FilterConfig; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import javax.servlet.annotation.WebFilter; 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | // 필터를 적용할 요청의 패턴 지정 - 모든 요청에 필터를 적용. 15 | @WebFilter(urlPatterns="/*") 16 | public class PerformanceFilter implements Filter { 17 | @Override 18 | public void init(FilterConfig filterConfig) throws ServletException { 19 | // 초기화 작업 20 | } 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 24 | throws IOException, ServletException { 25 | // 1. 전처리 작업 26 | long startTime = System.currentTimeMillis(); 27 | 28 | // 2. 서블릿 또는 다음 필터를 호출 29 | chain.doFilter(request, response); 30 | 31 | // 3. 후처리 작업 32 | System.out.print("["+((HttpServletRequest)request).getRequestURI()+"]"); 33 | System.out.println(" 소요시간="+(System.currentTimeMillis()-startTime)+"ms"); 34 | } 35 | 36 | @Override 37 | public void destroy() { 38 | // 정리 작업 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /ch2/Person.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | public class Person { 4 | private Car car = new Car(); 5 | public Car getCar() { return car; } 6 | } 7 | 8 | 9 | -------------------------------------------------------------------------------- /ch2/PrivateMethodCall.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | public class PrivateMethodCall { 6 | public static void main(String[] args) throws Exception{ 7 | // Hello hello = new Hello(); 8 | // hello.main(); // private이라서 외부 호출 불가 9 | 10 | // Reflection API를 사용 - 클래스 정보를 얻고 다룰 수 있는 강력한 기능제공 11 | // java.lang.reflect패키지를 제공 12 | // Hello클래스의 Class객체(클래스의 정보를 담고 있는 객체)를 얻어온다. 13 | Class helloClass = Class.forName("com.fastcampus.ch2.Hello"); 14 | Hello hello = (Hello)helloClass.newInstance(); // Class객체가 가진 정보로 객체 생성 15 | Method main = helloClass.getDeclaredMethod("main"); 16 | main.setAccessible(true); // private인 main()을 호출가능하게 한다. 17 | 18 | main.invoke(hello); // hello.main()와 같은 의미. main()이 private인데도 호출성공 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ch2/RegisterController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | import org.springframework.web.bind.annotation.ModelAttribute; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 9 | 10 | @Controller // ctrl+shift+o 자동 임포트 11 | public class RegisterController { 12 | // @RequestMapping(value="/register/add", method=RequestMethod.GET) // 신규회원 가입 13 | @GetMapping("/register/add") // 4.3부터 추가 14 | public String register() { 15 | return "registerForm"; // WEB-INF/views/registerForm.jsp 16 | } 17 | 18 | // @RequestMapping(value="/register/save", method=RequestMethod.POST) // 신규회원 가입 19 | // @PostMapping("/register/save") 20 | @PostMapping("/register/add") 21 | public String save(@ModelAttribute("user") User user, Model m) { 22 | if(!isValid(user)) { 23 | String msg = URLEncoder.encode("id를 잘못입력하셨습니다.", "utf-8"); 24 | 25 | m.addAttribute("msg", msg); 26 | return "redirect:/register/add"; // 신규회원 가입화면으로 이동(redirect) 27 | } 28 | 29 | return "registerInfo"; 30 | } 31 | 32 | private boolean isValid(User user) { 33 | return false; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ch2/RequestHeader.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Enumeration; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | @Controller 11 | public class RequestHeader { 12 | @RequestMapping("/requestHeader") 13 | public void main(HttpServletRequest request) { 14 | 15 | Enumeration e = request.getHeaderNames(); 16 | 17 | while (e.hasMoreElements()) { 18 | String name = e.nextElement(); 19 | System.out.println(name + ":" + request.getHeader(name)); 20 | } 21 | } 22 | } 23 | 24 | [실행결과] 25 | host:localhost:8080 26 | connection:keep-alive 27 | sec-ch-ua:"Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99" 28 | sec-ch-ua-mobile:?0 29 | sec-ch-ua-platform:"macOS" 30 | upgrade-insecure-requests:1 31 | user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 32 | accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 33 | sec-fetch-site:none 34 | sec-fetch-mode:navigate 35 | sec-fetch-user:?1 36 | sec-fetch-dest:document 37 | accept-encoding:gzip, deflate, br 38 | accept-language:ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7 39 | -------------------------------------------------------------------------------- /ch2/RequestInfo.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | 8 | @Controller 9 | public class RequestInfo { 10 | @RequestMapping("/requestInfo") 11 | // public static void main(String[] args) { 12 | public void main(HttpServletRequest request) { 13 | System.out.println("request.getCharacterEncoding()="+request.getCharacterEncoding()); // 요청 내용의 인코딩 14 | System.out.println("request.getContentLength()="+request.getContentLength()); // 요청 내용의 길이. 알수 없을 때는 -1 15 | System.out.println("request.getContentType()="+request.getContentType()); // 요청 내용의 타입. 알 수 없을 때는 null 16 | 17 | System.out.println("request.getMethod()="+request.getMethod()); // 요청 방법 18 | System.out.println("request.getProtocol()="+request.getProtocol()); // 프로토콜의 종류와 버젼 HTTP/1.1 19 | System.out.println("request.getScheme()="+request.getScheme()); // 프로토콜 20 | 21 | System.out.println("request.getServerName()="+request.getServerName()); // 서버 이름 또는 ip주소 22 | System.out.println("request.getServerPort()="+request.getServerPort()); // 서버 포트 23 | System.out.println("request.getRequestURL()="+request.getRequestURL()); // 요청 URL 24 | System.out.println("request.getRequestURI()="+request.getRequestURI()); // 요청 URI 25 | 26 | System.out.println("request.getContextPath()="+request.getContextPath()); // context path 27 | System.out.println("request.getServletPath()="+request.getServletPath()); // servlet path 28 | System.out.println("request.getQueryString()="+request.getQueryString()); // 쿼리 스트링 29 | 30 | System.out.println("request.getLocalName()="+request.getLocalName()); // 로컬 이름 31 | System.out.println("request.getLocalPort()="+request.getLocalPort()); // 로컬 포트 32 | 33 | System.out.println("request.getRemoteAddr()="+request.getRemoteAddr()); // 원격 ip주소 34 | System.out.println("request.getRemoteHost()="+request.getRemoteHost()); // 원격 호스트 또는 ip주소 35 | System.out.println("request.getRemotePort()="+request.getRemotePort()); // 원격 포트 36 | } 37 | } 38 | 39 | [실행결과] http://localhost:8080/ch2/requestInfo?year=2021&month=10&day=1 40 | request.getCharacterEncoding()=UTF-8 41 | request.getContentLength()=-1 42 | request.getContentType()=null 43 | request.getMethod()=GET 44 | request.getProtocol()=HTTP/1.1 45 | request.getScheme()=http 46 | request.getServerName()=localhost 47 | request.getServerPort()=8080 48 | request.getRequestURI()=http://localhost:8080/ch2/requestInfo 49 | request.getRequestURI()=/ch2/requestInfo 50 | request.getContextPath()=/ch2 51 | request.getServletPath()=/requestInfo 52 | request.getQueryString()=year=2021&month=10&day=1 53 | request.getLocalName()=localhost 54 | request.getLocalPort()=8080 55 | request.getRemoteAddr()=0:0:0:0:0:0:0:1 <--- AWS에 배포(deploy)한 다음에 실행하면, 실제 ip주소를 확인할 수 있음. 56 | request.getRemoteHost()=0:0:0:0:0:0:0:1 <--- AWS에 배포(deploy)한 다음에 실행하면, 실제 ip주소를 확인할 수 있음. 57 | request.getRemotePort()=54855 58 | -------------------------------------------------------------------------------- /ch2/RequestMappingTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class RequestMappingTest { 8 | // @RequestMapping({"/login/hello.do", "/login/hi.do"}) 9 | @RequestMapping("/login/hello.do") // http://localhost/ch2/login/hello.do 10 | public void test1(){ 11 | System.out.println("urlpattern=/login/hello.do"); 12 | } 13 | 14 | @RequestMapping("/login/*") // /login/hello, /login/hi 15 | public void test2(){ 16 | System.out.println("urlpattern=/login/*"); 17 | } 18 | 19 | @RequestMapping("/login/**/tmp/*.do") // /login/tmp/hello.do, /login/aaa/tmp/hello.do 20 | public void test3(){ 21 | System.out.println("urlpattern=/login/**/tmp/*.do"); 22 | } 23 | 24 | @RequestMapping("/login/??") 25 | public void test4(){ // /login/hi, /login/my.car 26 | System.out.println("urlpattern=/login/??"); 27 | } 28 | 29 | @RequestMapping("*.do") // /hello.do, /hi.do, /login/hi.do 30 | public void test5(){ 31 | System.out.println("urlpattern=*.do"); 32 | } 33 | 34 | @RequestMapping("/*.???") // /hello.aaa, /abc.txt 35 | public void test6(){ 36 | System.out.println("urlpattern=*.???"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ch2/RequestMessage.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Enumeration; 6 | import javax.servlet.http.HttpServletRequest; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | @Controller 11 | public class RequestMessage { 12 | @RequestMapping("/requestMessage") 13 | public void main(HttpServletRequest request) throws Exception { 14 | 15 | // 1. request line 16 | String requestLine = request.getMethod(); // GET 또는 POST 17 | requestLine += " " + request.getRequestURI(); // /ch2/requestMessage 18 | 19 | String queryString = request.getQueryString(); // year=2021&month=10&day=1 20 | requestLine += queryString == null ? "" : "?"+queryString; 21 | requestLine += " " + request.getProtocol(); // HTTP/1.1 22 | System.out.println(requestLine); 23 | 24 | 25 | // 2. request headers 26 | Enumeration e = request.getHeaderNames(); 27 | 28 | while (e.hasMoreElements()) { 29 | String name = e.nextElement(); 30 | System.out.println(name + ":" + request.getHeader(name)); 31 | } 32 | 33 | // 3. request body - POST일 때만 해당, GET은 body가 없음(CONTENT_LENGTH=0) 34 | final int CONTENT_LENGTH = request.getContentLength(); 35 | // System.out.println("content length="+CONTENT_LENGTH); 36 | 37 | if(CONTENT_LENGTH > 0) { 38 | byte[] content = new byte[CONTENT_LENGTH]; 39 | 40 | InputStream in = request.getInputStream(); 41 | in.read(content, 0, CONTENT_LENGTH); 42 | 43 | System.out.println(); // empty line 44 | System.out.println(new String(content, "utf-8")); // year=2021&month=10&day=1 45 | } // if 46 | } // main 47 | } 48 | 49 | 50 | [실행결과1] - GET 요청 51 | GET /ch2/requestMessage?year=2021&month=10&day=1 HTTP/1.1 <--- 요청 라인(request line) 52 | host:localhost:8080 53 | connection:keep-alive 54 | sec-ch-ua:"Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99" 55 | sec-ch-ua-mobile:?0 56 | sec-ch-ua-platform:"macOS" 57 | upgrade-insecure-requests:1 58 | user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 59 | accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 60 | sec-fetch-site:none 61 | sec-fetch-mode:navigate 62 | sec-fetch-user:?1 63 | sec-fetch-dest:document 64 | accept-encoding:gzip, deflate, br 65 | accept-language:ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7 66 | 67 | [실행결과2] - POST 요청 68 | POST /ch2/requestMessage HTTP/1.1 <--- 요청 라인(request line) 69 | host:localhost:8080 70 | connection:keep-alive 71 | content-length:90 72 | sec-ch-ua:"Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99" 73 | cache-control:no-cache 74 | content-type:application/x-www-form-urlencoded 75 | sec-ch-ua-mobile:?0 76 | user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36 77 | sec-ch-ua-platform:"macOS" 78 | accept:*/* 79 | origin:chrome-extension://coohjcphdfgbiolnekdpbcijmhambjff 80 | sec-fetch-site:none 81 | sec-fetch-mode:cors 82 | sec-fetch-dest:empty 83 | accept-encoding:gzip, deflate, br 84 | accept-language:ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7 85 | <--- empty line 86 | year=2021&month=10&day=1 <--- request body 87 | -------------------------------------------------------------------------------- /ch2/SetterCall.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import org.springframework.util.StringUtils; 10 | 11 | public class SetterCall { 12 | public static void main(String[] args) throws Exception{ 13 | Map map = new HashMap<>(); 14 | map.put("year", "2021"); 15 | map.put("month", "10"); 16 | map.put("day", "1"); 17 | 18 | Class type = Class.forName("com.fastcampus.ch2.MyDate"); 19 | 20 | // MyDate인스턴스를 생성하고, map의 값으로 초기화한다. 21 | Object obj = dataBind(map, type); 22 | System.out.println("obj="+obj); // obj=[year=2021, month=10, day=1] 23 | } // main 24 | 25 | private static Object dataBind(Map map, Class clazz) throws Exception { 26 | // 1. MyDate인스턴스 생성 27 | // Object obj = clazz.newInstance(); // deprecated method 28 | Object obj = clazz.getDeclaredConstructor().newInstance(new Object[0]); 29 | 30 | // 2. MyDate인스턴스의 setter를 호출해서, map의 값으로 MyDate를 초기화 31 | // 2-1. MyDate의 모든 iv를 돌면서 map에 있는지 찾는다. 32 | // 2-2. 찾으면, 찾은 값을 setter로 객체에 저장한다. 33 | Field[] ivArr = clazz.getDeclaredFields(); 34 | 35 | for(int i=0;i type = ivArr[i].getType(); 38 | 39 | // map에 같은 이름의 key가 있으면 가져와서 setter호출 40 | Object value = map.get(name); // 못찾으면 value의 값은 null 41 | Method method = null; 42 | 43 | try { // map에 iv와 일치하는 키가 있을 때만, setter를 호출 44 | if(value==null) continue; 45 | 46 | method = clazz.getDeclaredMethod(getSetterName(name), type); // setter의 정보 얻기 47 | System.out.println("method="+method); 48 | method.invoke(obj, convertTo(value, type)); // obj의 setter를 호출 49 | } catch(Exception e) { 50 | e.printStackTrace(); 51 | } 52 | } 53 | 54 | System.out.println(Arrays.toString(ivArr)); 55 | 56 | return obj; 57 | } 58 | 59 | private static Object convertTo(Object value, Class type) { 60 | // value의 타입과 type의 타입이 같으면 그대로 반환 61 | if(value==null || type==null || type.isInstance(value)) 62 | return value; 63 | 64 | // value의 타입과 type이 다르면, 변환해서 반환 65 | if(String.class.isInstance(value) && type==int.class) // String -> int 66 | return Integer.valueOf(""+value); 67 | 68 | return value; 69 | } 70 | 71 | // iv의 이름으로 setter의 이름을 만들어서 반환하는 메서드("day" -> "setDay") 72 | private static String getSetterName(String name) { 73 | // return "set"+name.substring(0,1).toUpperCase()+name.substring(1); 74 | return "set" + StringUtils.capitalize(name); // org.springframework.util.StringUtils 75 | } 76 | } 77 | 78 | /* 79 | [실행결과] 80 | method=public void com.fastcampus.ch2.MyDate.setYear(int) 81 | method=public void com.fastcampus.ch2.MyDate.setMonth(int) 82 | method=public void com.fastcampus.ch2.MyDate.setDay(int) 83 | [private int com.fastcampus.ch2.MyDate.year, private int com.fastcampus.ch2.MyDate.month, private int com.fastcampus.ch2.MyDate.day] 84 | obj=[year=2021, month=10, day=1] 85 | */ 86 | -------------------------------------------------------------------------------- /ch2/TwoDice.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | import java.io.IOException; 8 | import java.io.PrintWriter; 9 | 10 | @Controller 11 | public class TwoDice { 12 | @RequestMapping("/rollDice") 13 | // public static void main(String[] args) { 14 | public void main(HttpServletResponse response) throws IOException { 15 | int idx1 = (int)(Math.random()*6)+1; 16 | int idx2 = (int)(Math.random()*6)+1; 17 | 18 | response.setContentType("text/html"); 19 | response.setCharacterEncoding("utf-8"); 20 | PrintWriter out = response.getWriter(); 21 | out.println(""); 22 | out.println(""); 23 | out.println(""); 24 | out.println(""); 25 | out.println(""); 26 | out.println(""); 27 | out.println(""); 28 | out.println(""); 29 | out.close(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ch2/TwoDiceServlet.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.util.Random; 6 | 7 | import javax.servlet.annotation.WebServlet; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | @WebServlet("/rollDice2") 13 | public class TwoDiceServlet extends HttpServlet { 14 | int getRandomInt(int range) { 15 | return new Random().nextInt(range)+1; 16 | } 17 | 18 | public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 19 | int idx1 = getRandomInt(6); 20 | int idx2 = getRandomInt(6); 21 | 22 | response.setContentType("text/html"); 23 | response.setCharacterEncoding("utf-8"); 24 | PrintWriter out = response.getWriter(); 25 | out.println(""); 26 | out.println(""); 27 | out.println(""); 28 | out.println(""); 29 | out.println(""); 30 | out.println(""); 31 | out.println(""); 32 | out.println(""); 33 | out.close(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ch2/User.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Arrays; 4 | 5 | public class User { 6 | private String id; 7 | private String pwd; 8 | private String name; 9 | private String email; 10 | private String birth; 11 | private String[] sns; 12 | 13 | public String getId() { 14 | return id; 15 | } 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | public String getPwd() { 20 | return pwd; 21 | } 22 | public void setPwd(String pwd) { 23 | this.pwd = pwd; 24 | } 25 | public String getName() { 26 | return name; 27 | } 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | public String getEmail() { 32 | return email; 33 | } 34 | public void setEmail(String email) { 35 | this.email = email; 36 | } 37 | public String getBirth() { 38 | return birth; 39 | } 40 | public void setBirth(String birth) { 41 | this.birth = birth; 42 | } 43 | public String[] getSns() { 44 | return sns; 45 | } 46 | public void setSns(String[] sns) { 47 | this.sns = sns; 48 | } 49 | @Override 50 | public String toString() { 51 | return "User [id=" + id + ", pwd=" + pwd + ", name=" + name + ", email=" + email + ", birth=" + birth + ", sns=" 52 | + Arrays.toString(sns) + "]"; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ch2/UserValidator.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.validation.Errors; 4 | import org.springframework.validation.ValidationUtils; 5 | import org.springframework.validation.Validator; 6 | 7 | 8 | public class UserValidator implements Validator { 9 | @Override 10 | public boolean supports(Class clazz) { 11 | // return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인 12 | return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인 13 | } 14 | 15 | @Override 16 | public void validate(Object target, Errors errors) { 17 | System.out.println("LocalValidator.validate() is called"); 18 | 19 | User user = (User)target; 20 | 21 | String id = user.getId(); 22 | 23 | // if(id==null || "".equals(id.trim())) { 24 | // errors.rejectValue("id", "required"); 25 | // } 26 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required"); 27 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required"); 28 | 29 | if(id==null || id.length() < 5 || id.length() > 12) { 30 | errors.rejectValue("id", "invalidLength"); 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ch2/YoilTeller.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import java.io.IOException; 9 | import java.io.PrintWriter; 10 | import java.util.Calendar; 11 | 12 | @Controller 13 | public class YoilTeller { 14 | @RequestMapping("/getYoil") // http://localhost:8080/ch2/getYoil?year=2021&month=10&day=1 15 | // public static void main(String[] args) { 16 | public void main(HttpServletRequest request, HttpServletResponse response) throws IOException { 17 | // 1. 입력 18 | // String year = args[0]; 19 | // String month = args[1]; 20 | // String day = args[2]; 21 | String year = request.getParameter("year"); 22 | String month = request.getParameter("month"); 23 | String day = request.getParameter("day"); 24 | 25 | int yyyy = Integer.parseInt(year); 26 | int mm = Integer.parseInt(month); 27 | int dd = Integer.parseInt(day); 28 | 29 | // 2. 처리 30 | Calendar cal = Calendar.getInstance(); 31 | cal.set(yyyy, mm - 1, dd); 32 | 33 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 34 | char yoil = " 일월화수목금토".charAt(dayOfWeek); // 일요일:1, 월요일:2, ... 35 | 36 | // 3. 출력 37 | // System.out.println(year + "년 " + month + "월 " + day + "일은 "); 38 | // System.out.println(yoil + "요일입니다."); 39 | response.setContentType("text/html"); // 응답의 형식을 html로 지정 40 | response.setCharacterEncoding("utf-8"); // 응답의 인코딩을 utf-8로 지정 41 | PrintWriter out = response.getWriter(); // 브라우저로의 출력 스트림(out)을 얻는다. 42 | out.println(""); 43 | out.println(""); 44 | out.println(""); 45 | out.println(""); 46 | out.println(year + "년 " + month + "월 " + day + "일은 "); 47 | out.println(yoil + "요일입니다."); 48 | out.println(""); 49 | out.println(""); 50 | out.close(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | 10 | @Controller 11 | public class YoilTellerMVC { 12 | @RequestMapping("/getYoilMVC") // http://localhost/ch2/getYoilMVC 13 | public String main(int year, int month, int day, Model model) { 14 | 15 | // 1. 유효성 검사 16 | if(!isValid(year, month, day)) 17 | return "yoilError"; // 유효하지 않으면, /WEB-INF/views/yoilError.jsp로 이동 18 | 19 | // 2. 처리 20 | char yoil = getYoil(year, month, day); 21 | 22 | // 3. Model에 작업 결과 저장 23 | model.addAttribute("year", year); 24 | model.addAttribute("month", month); 25 | model.addAttribute("day", day); 26 | model.addAttribute("yoil", yoil); 27 | 28 | // 4. 작업 결과를 보여줄 View의 이름을 반환 29 | return "yoil"; // /WEB-INF/views/yoil.jsp 30 | } 31 | 32 | private char getYoil(int year, int month, int day) { 33 | Calendar cal = Calendar.getInstance(); 34 | cal.set(year, month - 1, day); 35 | 36 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 37 | return " 일월화수목금토".charAt(dayOfWeek); 38 | } 39 | 40 | private boolean isValid(int year, int month, int day) { 41 | if(year==-1 || month==-1 || day==-1) 42 | return false; 43 | 44 | return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC2.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | @Controller 12 | public class YoilTellerMVC2 { 13 | @ExceptionHandler(Exception.class) 14 | public String catcher(Exception ex) { 15 | return "yoilError"; 16 | } 17 | 18 | @RequestMapping("/getYoilMVC2") // http://localhost/ch2/getYoilMVC2 19 | public String main(@RequestParam(required=true) int year, 20 | @RequestParam(required=true) int month, 21 | @RequestParam(required=true) int day, Model model) { 22 | 23 | // 1. 유효성 검사 24 | if(!isValid(year, month, day)) 25 | return "yoilError"; // 유효하지 않으면, /WEB-INF/views/yoilError.jsp로 이동 26 | 27 | // 2. 처리 28 | char yoil = getYoil(year, month, day); 29 | 30 | // 3. Model에 작업 결과 저장 31 | model.addAttribute("year", year); 32 | model.addAttribute("month", month); 33 | model.addAttribute("day", day); 34 | model.addAttribute("yoil", yoil); 35 | 36 | // 4. 작업 결과를 보여줄 View의 이름을 반환 37 | return "yoil"; // /WEB-INF/views/yoil.jsp 38 | } 39 | 40 | private char getYoil(int year, int month, int day) { 41 | Calendar cal = Calendar.getInstance(); 42 | cal.set(year, month - 1, day); 43 | 44 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 45 | return " 일월화수목금토".charAt(dayOfWeek); 46 | } 47 | 48 | private boolean isValid(int year, int month, int day) { 49 | if(year==-1 || month==-1 || day==-1) 50 | return false; 51 | 52 | return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC3.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | @Controller 11 | public class YoilTellerMVC3 { 12 | @RequestMapping("/getYoilMVC3") // http://localhost/ch2/getYoilMVC3 13 | public ModelAndView main( // 반환 타입이 ModelAndView 14 | @RequestParam(defaultValue="-1") int year, 15 | @RequestParam(defaultValue="-1") int month, 16 | @RequestParam(defaultValue="-1") int day 17 | ) { 18 | 19 | // 1. ModelAndView를 생성 20 | ModelAndView mv = new ModelAndView(); 21 | 22 | // 2. 유효성 검사 23 | if(!isValid(year, month, day)) { 24 | mv.setViewName("yoilError"); // View의 이름을 지정 25 | return mv; 26 | } 27 | 28 | // 3. 처리 29 | char yoil = getYoil(year, month, day); 30 | 31 | // 4. ModelAndView에 작업한 결과를 저장 32 | mv.addObject("year", year); 33 | mv.addObject("month", month); 34 | mv.addObject("day", day); 35 | mv.addObject("yoil", yoil); 36 | 37 | // 5. 작업 결과를 보여줄 View의 이름을 지정 38 | mv.setViewName("yoil"); 39 | 40 | // 6. ModelAndView를 반환 41 | return mv; 42 | } 43 | 44 | private char getYoil(int year, int month, int day) { 45 | Calendar cal = Calendar.getInstance(); 46 | cal.set(year, month - 1, day); 47 | 48 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 49 | return " 일월화수목금토".charAt(dayOfWeek); 50 | } 51 | 52 | private boolean isValid(int year, int month, int day) { 53 | if(year==-1 || month==-1 || day==-1) 54 | return false; 55 | 56 | return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC4.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestParam; 8 | import org.springframework.web.servlet.ModelAndView; 9 | 10 | @Controller 11 | public class YoilTellerMVC4 { 12 | @RequestMapping("/getYoilMVC4") // http://localhost/ch2/getYoilMVC4?year=2021&month=10&day=1 13 | public ModelAndView main(MyDate date) { // 반환 타입이 ModelAndView 14 | System.out.println("date="+date); 15 | 16 | // 1. ModelAndView를 생성 17 | ModelAndView mv = new ModelAndView(); 18 | 19 | // 2. 유효성 검사 20 | if(!isValid(date)) { 21 | mv.setViewName("yoilError"); // 뷰의 이름을 지정 22 | return mv; 23 | } 24 | 25 | // 3. 처리 26 | char yoil = getYoil(date); 27 | 28 | // 4. ModelAndView에 작업한 결과를 저장 29 | //mv.addObject("year", date.getYear()); 30 | //mv.addObject("month", date.getMonth()); 31 | //mv.addObject("day", date.getDay()); 32 | mv.addObject("myDate", date); 33 | mv.addObject("yoil", yoil); 34 | 35 | // 5. 작업 결과를 보여줄 뷰의 이름을 지정 36 | mv.setViewName("yoil"); 37 | 38 | // 6. ModelAndView를 반환 39 | return mv; 40 | } 41 | 42 | private char getYoil(MyDate date) { 43 | return getYoil(date.getYear(), date.getMonth(), date.getDay()); 44 | } 45 | 46 | private char getYoil(int year, int month, int day) { 47 | Calendar cal = Calendar.getInstance(); 48 | cal.set(year, month - 1, day); 49 | 50 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 51 | return " 일월화수목금토".charAt(dayOfWeek); 52 | } 53 | 54 | private boolean isValid(MyDate date) { 55 | return isValid(date.getYear(), date.getMonth(), date.getDay()); 56 | } 57 | 58 | private boolean isValid(int year, int month, int day) { 59 | if(year==-1 || month==-1 || day==-1) 60 | return false; 61 | 62 | return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC5.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.ModelAttribute; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | 10 | @Controller 11 | public class YoilTellerMVC5 { 12 | @ExceptionHandler(Exception.class) 13 | public String catcher(Exception ex) { 14 | System.out.println("ex="+ex); 15 | 16 | return "yoilError"; 17 | } 18 | 19 | @RequestMapping("/getYoilMVC5") // http://localhost/ch2/getYoilMVC5?year=2021&month=10&day=1 20 | // public String main(@ModelAttribute("myDate") MyDate date, Model m) { // 아래와 동일 21 | public String main(@ModelAttribute MyDate date, Model m) { // @ModelAttribute사용, 반환 타입은 String 22 | System.out.println("myDate="+date); 23 | 24 | // 1. 유효성 검사 25 | if(!isValid(date)) 26 | return "yoilError"; 27 | 28 | // 2. 처리 29 | char yoil = getYoil(date); 30 | 31 | // 3. Model에 작업한 결과를 저장 32 | // @ModelAttribute 덕분에 MyDate를 저장안해도 됨. View로 자동 전달됨. 33 | // m.addAttribute("myDate", date); 34 | // m.addAttribute("yoil", yoil); 35 | 36 | // 4. 작업 결과를 보여줄 뷰의 이름을 반환 37 | return "yoil"; 38 | } 39 | 40 | private @ModelAttribute("yoil") char getYoil(MyDate date) { 41 | return getYoil(date.getYear(), date.getMonth(), date.getDay()); 42 | } 43 | 44 | private char getYoil(int year, int month, int day) { 45 | Calendar cal = Calendar.getInstance(); 46 | cal.set(year, month - 1, day); 47 | 48 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 49 | return " 일월화수목금토".charAt(dayOfWeek); 50 | } 51 | 52 | private boolean isValid(MyDate date) { 53 | return isValid(date.getYear(), date.getMonth(), date.getDay()); 54 | } 55 | 56 | private boolean isValid(int year, int month, int day) { 57 | if(year==-1 || month==-1 || day==-1) 58 | return false; 59 | 60 | return (1<=month && month<=12) && (1<=day && day<=31); // 간단히 체크 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ch2/YoilTellerMVC6.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.validation.BindingResult; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ModelAttribute; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | 13 | @Controller 14 | public class YoilTellerMVC6 { 15 | @ExceptionHandler(Exception.class) 16 | public String catcher(Exception ex, BindingResult result) { 17 | System.out.println("result="+result); 18 | System.out.println("error="+result.getFieldError()); 19 | 20 | return "yoilError"; 21 | } 22 | 23 | @RequestMapping("/getYoilMVC6") // http://localhost/ch2/getYoilMVC6 24 | // public String main(@ModelAttribute("myDate") MyDate date, Model model) { 25 | public String main(MyDate date, BindingResult result) { 26 | System.out.println("result="+result); 27 | // 1. 유효성 검사 28 | if(!isValid(date)) 29 | return "yoilError"; // 유효하지 않으면, /WEB-INF/views/yoilError.jsp로 이동 30 | 31 | // 2. 처리 32 | // char yoil = getYoil(date); 33 | 34 | // 3. Model에 작업 결과 저장 35 | // model.addAttribute("myDate", date); 36 | // model.addAttribute("yoil", yoil); 37 | 38 | // 4. 작업 결과를 보여줄 View의 이름을 반환 39 | return "yoil"; // /WEB-INF/views/yoil.jsp 40 | } 41 | 42 | 43 | private @ModelAttribute("yoil") char getYoil(MyDate date) { 44 | return getYoil(date.getYear(), date.getMonth(), date.getDay()); 45 | } 46 | 47 | private char getYoil(int year, int month, int day) { 48 | Calendar cal = Calendar.getInstance(); 49 | cal.set(year, month - 1, day); 50 | 51 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 52 | return " 일월화수목금토".charAt(dayOfWeek); 53 | } 54 | 55 | private boolean isValid(MyDate date) { 56 | if(date.getYear()==-1 || date.getMonth()==-1 || date.getDay()==-1) 57 | return false; 58 | 59 | return (1<=date.getMonth() && date.getMonth()<=12) && (1<=date.getDay() && date.getDay()<=31); // 간단히 체크 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ch2/YoilTellerServlet.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch2; 2 | 3 | import java.io.IOException; 4 | import java.io.PrintWriter; 5 | import java.util.Calendar; 6 | 7 | import javax.servlet.annotation.WebServlet; 8 | import javax.servlet.http.HttpServlet; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | @WebServlet("/getYoil2") 13 | public class YoilTellerServlet extends HttpServlet { 14 | @Override 15 | public void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 16 | // 1. 입력 17 | String year = request.getParameter("year"); 18 | String month = request.getParameter("month"); 19 | String day = request.getParameter("day"); 20 | 21 | int yyyy = Integer.parseInt(year); 22 | int mm = Integer.parseInt(month); 23 | int dd = Integer.parseInt(day); 24 | 25 | // 2. 처리 26 | Calendar cal = Calendar.getInstance(); 27 | cal.set(yyyy, mm - 1, dd); 28 | 29 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 30 | char yoil = " 일월화수목금토".charAt(dayOfWeek); 31 | 32 | // 3. 출력 33 | response.setContentType("text/html"); // 응답의 형식을 html로 지정 34 | response.setCharacterEncoding("utf-8"); // 응답의 인코딩을 utf-8로 지정 35 | 36 | PrintWriter out = response.getWriter(); // 브라우저로의 출력 스트림(out)을 얻는다. 37 | out.println(""); 38 | out.println(""); 39 | out.println(""); 40 | out.println(""); 41 | out.println(year + "년 " + month + "월 " + day + "일은 "); 42 | out.println(yoil + "요일입니다."); 43 | out.println(""); 44 | out.println(""); 45 | out.println(""); 46 | out.close(); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /ch2/boardList.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | 4 | 5 | 6 | 7 | 8 | fastcampus 9 | 10 | 11 | 12 |
22 |

This is BOARD

23 |

This is BOARD

24 |

This is BOARD

25 |

This is BOARD

26 |

This is BOARD

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /ch2/dice.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch2/dice.zip -------------------------------------------------------------------------------- /ch2/el.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 3 | <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 4 | <%@ page import="com.fastcampus.ch2.*" %> 5 | <% 6 | Person person = new Person(); 7 | request.setAttribute("person", person); 8 | request.setAttribute("name", "남궁성"); 9 | request.setAttribute("list", new java.util.ArrayList()); 10 | %> 11 | 12 | 13 | EL 14 | 15 | 16 | person.getCar().getColor()=<%=person.getCar().getColor()%>
17 | person.getCar().getColor()=${person.getCar().getColor()}
18 | person.getCar().getColor()=${person.car.color}
19 | name=<%=request.getAttribute("name")%>
20 | name=${requestScope.name}
21 | name=${name}
22 | id=<%=request.getParameter("id")%>
23 | id=${pageContext.request.getParameter("id")}
24 | id=${param.id}
25 | "1"+1 = ${"1"+1}
26 | "1"+="1" = ${"1"+="1"}
27 | "2">1 = ${"2">1}
28 | null = ${null}
29 | null+1 = ${null+1}
30 | null+null = ${null+null}
31 | "" + null = ${""+null}
32 | ""-1 = ${""-1}
33 | empty null=${empty null}
34 | empty list=${empty list}
35 | null==0 = ${null==0}
36 | null eq 0 = ${null eq 0}
37 | name == "남궁성"=${name=="남궁성"}
38 | name != "남궁성"=${name!="남궁성"}
39 | name eq "남궁성"=${name eq "남궁성"}
40 | name ne "남궁성"=${name ne "남궁성"}
41 | name.equals("남궁성")=${name.equals("남궁성")}
42 | 43 | 44 | 45 | [실행결과] 46 | person.getCar().getColor()=red 47 | person.getCar().getColor()=red 48 | person.car.color=red 49 | name=남궁성 50 | name=남궁성 51 | name=남궁성 52 | id=asdf 53 | id=asdf 54 | id=asdf 55 | "1"+1 = 2 56 | "1"+="1" = 11 57 | "2">1 = true 58 | null = 59 | null+1 = 1 60 | null+null = 0 61 | "" + null = 0 62 | ""-1 = -1 63 | empty null=true 64 | empty list=true 65 | null==0 = false 66 | null eq 0 = false 67 | name == "남궁성"=true 68 | name != "남궁성"=false 69 | name eq "남궁성"=true 70 | name ne "남궁성"=false 71 | name.equals("남궁성")=true 72 | -------------------------------------------------------------------------------- /ch2/error.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | 4 | 5 | error.jsp 6 | 7 | 8 |

예외가 발생했습니다.

9 | 발생한 예외 : ${ex}
10 | 예외 메시지 : ${ex.message}
11 |
    12 | 13 |
  1. ${i.toString()}
  2. 14 |
    15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ch2/error_message.properties: -------------------------------------------------------------------------------- 1 | required=필수 항목 입니다. 2 | required.user.pwd=사용자 비밀번호는 필수 항목입니다. 3 | invalidLength.id=아이디의 길이는 {0}~{1}사이어야 합니다. 4 | -------------------------------------------------------------------------------- /ch2/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | 4 | 5 | 6 | 7 | fastcampus 8 | 9 | 10 | 11 | 12 | 22 |
23 |

This is HOME

24 |

This is HOME

25 |

This is HOME

26 |
27 | -------------------------------------------------------------------------------- /ch2/jstl.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> 3 | <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 4 | 5 | 6 | JSTL 7 | 8 | 9 | 10 | 11 | 12 | ${i} 13 | 14 |
15 | 16 | 17 | ${status.count}. arr[${status.index}]=${elem}
18 |
19 |
20 | 21 | msg=${param.msg} 22 | msg= 23 | 24 |
25 | 메시지가 없습니다.
26 | 27 | 28 | 성인입니다. 29 | 성인이 아닙니다. 30 | 값이 유효하지 않습니다. 31 | 32 |
33 | 34 | Server time is 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ch2/loginForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page import="java.net.URLDecoder" %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | Login 11 | 12 | 58 | 59 | 60 |
61 |

Login

62 |
63 | 64 | ${URLDecoder.decode(param.msg)} 65 | 66 |
67 | 68 | 69 | 70 |
71 | | 72 | 비밀번호 찾기 | 73 | 회원가입 74 |
75 | 100 |
101 | 102 | 103 | -------------------------------------------------------------------------------- /ch2/menu.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin : 0; 4 | padding: 0; 5 | } 6 | 7 | a { text-decoration: none; } 8 | 9 | ul { 10 | list-style-type: none; 11 | height: 48px; 12 | width: 100%; 13 | background-color: #30426E; 14 | display: flex; 15 | } 16 | 17 | ul > li { 18 | color: lightgray; 19 | height : 100%; 20 | width:90px; 21 | display:flex; 22 | align-items: center; 23 | } 24 | 25 | ul > li > a { 26 | color: lightgray; 27 | margin:auto; 28 | padding: 10px; 29 | font-size:20px; 30 | align-items: center; 31 | } 32 | 33 | ul > li > a:hover { 34 | color :white; 35 | border-bottom: 3px solid rgb(209, 209, 209); 36 | } 37 | 38 | #logo { 39 | color:white; 40 | font-size: 18px; 41 | padding-left:40px; 42 | margin-right:auto; 43 | display: flex; 44 | } 45 | -------------------------------------------------------------------------------- /ch2/registerForm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 66 | Register 67 | 68 | 69 |
70 |
Register
71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 | 84 | 85 | 86 |
87 | 88 |
89 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /ch2/registerForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8" %> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page import="java.net.URLDecoder"%> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 70 | Register 71 | 72 | 73 |
" method="post" onsubmit="return formCheck(this)"> 74 |
Register
75 |
76 | 77 | ${URLDecoder.decode(param.msg)} 78 | 79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 | 92 | 93 | 94 |
95 | 96 |
97 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /ch2/registerInfo.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | Insert title here 8 | 9 | 10 |

id=${param.id}

11 |

pwd=${param.pwd}

12 |

name=${param.name}

13 |

email=${param.email}

14 |

birth=${param.birth}

15 |

sns=${param.sns}

16 | 17 | 18 | -------------------------------------------------------------------------------- /ch2/servlet-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | error400 32 | 33 | 34 | 35 | 36 | 400 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | error_message 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ch2/twoDice.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ page import="java.util.Random" %> 3 | <%-- <%! 클래스 영역 %> --%> 4 | <%! 5 | int getRandomInt(int range){ 6 | return new Random().nextInt(range)+1; 7 | } 8 | %> 9 | <%-- <% 메서드 영역 - service()의 내부 %> --%> 10 | <% 11 | int idx1 = getRandomInt(6); 12 | int idx2 = getRandomInt(6); 13 | %> 14 | 15 | 16 | twoDice.jsp 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ch2/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | contextConfigLocation 9 | /WEB-INF/spring/root-context.xml 10 | 11 | 12 | 13 | 14 | org.springframework.web.context.ContextLoaderListener 15 | 16 | 17 | 18 | 19 | appServlet 20 | org.springframework.web.servlet.DispatcherServlet 21 | 22 | contextConfigLocation 23 | /WEB-INF/spring/appServlet/servlet-context.xml 24 | 25 | 26 | listings 27 | true 28 | 29 | 1 30 | 31 | 32 | 33 | appServlet 34 | / 35 | 36 | 37 | 38 | 39 | encodingFilter 40 | org.springframework.web.filter.CharacterEncodingFilter 41 | 42 | encoding 43 | UTF-8 44 | 45 | 46 | forceEncoding 47 | true 48 | 49 | 50 | 51 | 52 | encodingFilter 53 | /* 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ch2/yoil.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8" %> 2 | 3 | 4 | YoilTellerMVC 5 | 6 | 7 |

${year}년 ${month}월 ${day}일은 ${yoil}요일입니다.

8 | 9 | 10 | -------------------------------------------------------------------------------- /ch2/yoilError.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8" %> 2 | 3 | 4 | YoilTellerMVC 5 | 6 | 7 |

잘못된 요청입니다. 다시 요청해 주세요.

8 |

year, month, day를 모두 올바른 값으로 입력하셔야합니다.

9 | 10 | 11 | -------------------------------------------------------------------------------- /ch2/yoilTeller.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ page import="java.util.Calendar" %> 3 | <% 4 | String year = request.getParameter("year"); 5 | String month = request.getParameter("month"); 6 | String day = request.getParameter("day"); 7 | 8 | int yyyy = Integer.parseInt(year); 9 | int mm = Integer.parseInt(month); 10 | int dd = Integer.parseInt(day); 11 | 12 | // 2. 처리 13 | Calendar cal = Calendar.getInstance(); 14 | cal.set(yyyy, mm - 1, dd); 15 | 16 | int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); 17 | char yoil = " 일월화수목금토".charAt(dayOfWeek); 18 | 19 | // 3. 출력 20 | %> 21 | 22 | 23 | yoilTeller.jsp 24 | 25 | 26 |

<%=yyyy%>년 <%=mm%>월 <%=dd%>일은 <%=yoil%>요일입니다.

27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ch3/AopMain.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3.aop; 2 | 3 | import org.springframework.transaction.annotation.Transactional; 4 | 5 | import java.lang.reflect.Method; 6 | import java.util.regex.Matcher; 7 | import java.util.regex.Pattern; 8 | 9 | public class AopMain { 10 | public static void main(String[] args) throws Exception { 11 | MyAdvice myAdvice = new MyAdvice(); 12 | 13 | Class myClass = Class.forName("com.fastcampus.ch3.aop.MyClass"); 14 | Object obj = myClass.newInstance(); 15 | 16 | for(Method m : myClass.getDeclaredMethods()) { 17 | myAdvice.invoke(m, obj, null); 18 | } 19 | } 20 | } 21 | 22 | class MyAdvice { 23 | Pattern p = Pattern.compile("a.*"); 24 | 25 | boolean matches(Method m){ 26 | Matcher matcher = p.matcher(m.getName()); 27 | return matcher.matches(); 28 | } 29 | 30 | void invoke(Method m, Object obj, Object... args) throws Exception { 31 | if(m.getAnnotation(Transactional.class)!=null) 32 | System.out.println("[before]{"); 33 | 34 | m.invoke(obj, args); // aaa(), aaa2(), bbb() 호출가능 35 | 36 | if(m.getAnnotation(Transactional.class)!=null) 37 | System.out.println("}[after]"); 38 | } 39 | } 40 | 41 | class MyClass { 42 | @Transactional 43 | void aaa() { 44 | System.out.println("aaa() is called."); 45 | } 46 | void aaa2() { 47 | System.out.println("aaa2() is called."); 48 | } 49 | void bbb() { 50 | System.out.println("bbb() is called."); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /ch3/DBConnectionTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import java.sql.*; 4 | 5 | public class DBConnectionTest { 6 | public static void main(String[] args) throws Exception { 7 | // 스키마의 이름(springbasic)이 다른 경우 알맞게 변경해야 함 8 | String DB_URL = "jdbc:mysql://localhost:3306/springbasic?useUnicode=true&characterEncoding=utf8"; 9 | 10 | // DB의 userid와 pwd를 알맞게 변경해야 함 11 | String DB_USER = "asdf"; 12 | String DB_PASSWORD = "1234"; 13 | 14 | Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); // 데이터베이스의 연결을 얻는다. 15 | Statement stmt = conn.createStatement(); // Statement를 생성한다. 16 | 17 | String query = "SELECT now()"; // 시스템의 현재 날짜시간을 출력하는 쿼리(query) 18 | ResultSet rs = stmt.executeQuery(query); // query를 실행한 결과를 rs에 담는다. 19 | 20 | // 실행결과가 담긴 rs에서 한 줄씩 읽어서 출력 21 | while (rs.next()) { 22 | String curDate = rs.getString(1); // 읽어온 행의 첫번째 컬럼의 값을 String으로 읽어서 curDate에 저장 23 | System.out.println(curDate); // 2022-01-11 13:53:00.0 24 | } 25 | } // main() 26 | } 27 | 28 | /* [실행결과] 29 | 2022-01-11 13:53:00.0 30 | */ 31 | -------------------------------------------------------------------------------- /ch3/DBConnectionTest2.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import org.junit.*; 4 | import org.springframework.context.*; 5 | import org.springframework.context.support.*; 6 | import org.springframework.jdbc.datasource.*; 7 | 8 | import javax.sql.*; 9 | import java.sql.*; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | public class DBConnectionTest2 { 14 | @Test 15 | public void jdbcConnectionTest() throws Exception { 16 | // // 스키마의 이름(springbasic)이 다른 경우 알맞게 변경 17 | // String DB_URL = "jdbc:mysql://localhost:3306/springbasic?useUnicode=true&characterEncoding=utf8"; 18 | // 19 | // // DB의 userid와 pwd를 알맞게 변경 20 | // String DB_USER = "asdf"; 21 | // String DB_PASSWORD = "1234"; 22 | // String DB_DRIVER = "com.mysql.jdbc.Driver"; 23 | // 24 | // DriverManagerDataSource ds = new DriverManagerDataSource(); 25 | // ds.setDriverClassName(DB_DRIVER); 26 | // ds.setUrl(DB_URL); 27 | // ds.setUsername(DB_USER); 28 | // ds.setPassword(DB_PASSWORD); 29 | 30 | ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml"); 31 | DataSource ds = ac.getBean(DataSource.class); 32 | 33 | Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다. 34 | 35 | System.out.println("conn = " + conn); 36 | assertTrue(conn!=null); 37 | } 38 | } 39 | 40 | /* [root-context.xml] 41 | 42 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | */ 55 | -------------------------------------------------------------------------------- /ch3/DBConnectionTest3.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import org.junit.*; 4 | import org.junit.runner.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.context.*; 7 | import org.springframework.context.support.*; 8 | import org.springframework.jdbc.datasource.*; 9 | import org.springframework.test.context.*; 10 | import org.springframework.test.context.junit4.*; 11 | 12 | import javax.sql.*; 13 | import java.sql.*; 14 | 15 | import static org.junit.Assert.*; 16 | 17 | @RunWith(SpringJUnit4ClassRunner.class) 18 | @ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) 19 | public class DBConnectionTest3 { 20 | @Autowired 21 | DataSource ds; // 컨테이너로부터 자동 주입받는다. 22 | 23 | @Test 24 | public void jdbcConnectionTest() throws Exception { 25 | // ApplicationContext ac = new GenericXmlApplicationContext("file:src/main/webapp/WEB-INF/spring/**/root-context.xml"); 26 | // DataSource ds = ac.getBean(DataSource.class); 27 | 28 | Connection conn = ds.getConnection(); // 데이터베이스의 연결을 얻는다. 29 | 30 | System.out.println("conn = " + conn); 31 | assertTrue(conn!=null); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ch3/HomeController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import java.util.*; 4 | 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.context.*; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.context.*; 12 | import org.springframework.web.context.support.*; 13 | 14 | import javax.servlet.*; 15 | import javax.servlet.http.*; 16 | 17 | @Controller 18 | public class HomeController { 19 | @Autowired 20 | WebApplicationContext servletAC; // Servlet AC 21 | 22 | @RequestMapping(value = "/", method = RequestMethod.GET) 23 | public String home(Locale locale, HttpServletRequest request, Model model) { 24 | // 원래는 request.getServletContext()지만, 컨트롤러는 HttpServlet을 상속받지 않아서 아래와 같이 해야함. 25 | ServletContext sc = request.getSession().getServletContext(); // ApplicationContextFacade 26 | WebApplicationContext rootAC = WebApplicationContextUtils.getWebApplicationContext(sc); // Root AC 27 | 28 | System.out.println("webApplicationContext = " + rootAC); 29 | System.out.println("servletAC = " + servletAC); 30 | 31 | System.out.println("rootAC.getBeanDefinitionNames() = " + Arrays.toString(rootAC.getBeanDefinitionNames())); 32 | System.out.println("servletAC.getBeanDefinitionNames() = " + Arrays.toString(servletAC.getBeanDefinitionNames())); 33 | 34 | System.out.println("rootAC.getBeanDefinitionCount() = " + rootAC.getBeanDefinitionCount()); 35 | System.out.println("servletAC.getBeanDefinitionCount() = " + servletAC.getBeanDefinitionCount()); 36 | 37 | System.out.println("servletAC.getParent()==rootAC = " + (servletAC.getParent() == rootAC)); // servletAC.getParent()==rootAC = true 38 | return "home"; 39 | } 40 | } 41 | /* [실행결과] 42 | webApplicationContext = Root WebApplicationContext: startup date [Thu Jan 06 16:26:50 KST 2022]; root of context hierarchy 43 | servletAC = WebApplicationContext for namespace 'appServlet-servlet': startup date [Thu Jan 06 16:26:51 KST 2022]; parent: Root WebApplicationContext 44 | rootAC.getBeanDefinitionNames() = [] 45 | servletAC.getBeanDefinitionNames() = [mvcContentNegotiationManager, org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping, mvcCorsConfigurations, org.springframework.format.support.FormattingConversionServiceFactoryBean#0, org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter, mvcUriComponentsContributor, org.springframework.web.servlet.handler.MappedInterceptor#0, org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0, org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0, org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter, mvcHandlerMappingIntrospector, mvcResourceUrlProvider, org.springframework.web.servlet.handler.MappedInterceptor#1, mvcPathMatcher, mvcUrlPathHelper, org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0, org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0, org.springframework.web.servlet.view.InternalResourceViewResolver#0, car, door, engine, homeController, superEngine, turboEngine, org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory] 46 | rootAC.getBeanDefinitionCount() = 0 47 | servletAC.getBeanDefinitionCount() = 33 48 | servletAC.getParent()==rootAC = true 49 | */ 50 | -------------------------------------------------------------------------------- /ch3/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import java.net.URLEncoder; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import javax.servlet.http.HttpSession; 9 | 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.CookieValue; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | 16 | @Controller 17 | @RequestMapping("/login") 18 | public class LoginController { 19 | @GetMapping("/login") 20 | public String loginForm() { 21 | return "loginForm"; 22 | } 23 | 24 | @GetMapping("/logout") 25 | public String logout(HttpSession session) { 26 | // 1. 세션을 종료 27 | session.invalidate(); 28 | // 2. 홈으로 이동 29 | return "redirect:/"; 30 | } 31 | 32 | @PostMapping("/login") 33 | public String login(String id, String pwd, String toURL, boolean rememberId, 34 | HttpServletRequest request, HttpServletResponse response) throws Exception { 35 | 36 | // 1. id와 pwd를 확인 37 | if(!loginCheck(id, pwd)) { 38 | // 2-1 일치하지 않으면, loginForm으로 이동 39 | String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", "utf-8"); 40 | 41 | return "redirect:/login/login?msg="+msg; 42 | } 43 | // 2-2. id와 pwd가 일치하면, 44 | // 세션 객체를 얻어오기 45 | HttpSession session = request.getSession(); 46 | // 세션 객체에 id를 저장 47 | session.setAttribute("id", id); 48 | 49 | if(rememberId) { 50 | // 1. 쿠키를 생성 51 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 52 | // 2. 응답에 저장 53 | response.addCookie(cookie); 54 | } else { 55 | // 1. 쿠키를 삭제 56 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 57 | cookie.setMaxAge(0); // 쿠키를 삭제 58 | // 2. 응답에 저장 59 | response.addCookie(cookie); 60 | } 61 | // 3. 홈으로 이동 62 | toURL = toURL==null || toURL.equals("") ? "/" : toURL; 63 | 64 | return "redirect:"+toURL; 65 | } 66 | 67 | private boolean loginCheck(String id, String pwd) { 68 | return "asdf".equals(id) && "1234".equals(pwd); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ch3/RegisterController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import java.net.URLEncoder; 4 | import java.util.List; 5 | 6 | import javax.validation.Valid; 7 | 8 | import org.springframework.beans.propertyeditors.StringArrayPropertyEditor; 9 | import org.springframework.core.convert.ConversionService; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.validation.BindingResult; 13 | import org.springframework.validation.Validator; 14 | import org.springframework.web.bind.WebDataBinder; 15 | import org.springframework.web.bind.annotation.InitBinder; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestMethod; 19 | 20 | @Controller // ctrl+shift+o 자동 import 21 | @RequestMapping("/register") 22 | public class RegisterController { 23 | 24 | @InitBinder 25 | public void toDate(WebDataBinder binder) { 26 | SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 27 | binder.registerCustomEditor(Date.class, new CustomDateEditor(df, false)); 28 | binder.setValidator(new UserValidator()); // UserValidator를 WebDataBinder의 로컬 validator로 등록 29 | // List validatorList = binder.getValidators(); 30 | // System.out.println("validatorList="+validatorList); 31 | } 32 | 33 | @GetMapping("/add") 34 | public String register() { 35 | return "registerForm"; // WEB-INF/views/registerForm.jsp 36 | } 37 | 38 | @PostMapping("/add") 39 | public String save(@Valid User user, BindingResult result, Model m) throws Exception { 40 | System.out.println("result="+result); 41 | System.out.println("user="+user); 42 | 43 | // User객체를 검증한 결과 에러가 있으면, registerForm을 이용해서 에러를 보여줘야 함. 44 | if(result.hasErrors()) { 45 | return "registerForm"; 46 | } 47 | 48 | // 2. DB에 신규회원 정보를 저장 49 | return "registerInfo"; 50 | } 51 | 52 | private boolean isValid(User user) { 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ch3/User.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import java.util.Date; 4 | import java.util.Objects; 5 | 6 | public class User { 7 | private String id; 8 | private String pwd; 9 | private String name; 10 | private String email; 11 | private Date birth; 12 | private String sns; 13 | private Date reg_date; 14 | 15 | public User(){} 16 | public User(String id, String pwd, String name, String email, Date birth, String sns, Date reg_date) { 17 | this.id = id; 18 | this.pwd = pwd; 19 | this.name = name; 20 | this.email = email; 21 | this.birth = birth; 22 | this.sns = sns; 23 | this.reg_date = reg_date; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) return true; 29 | if (o == null || getClass() != o.getClass()) return false; 30 | User user = (User) o; 31 | 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); 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return Objects.hash(id, pwd, name, email, birth, sns, reg_date); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "User{" + 42 | "id='" + id + '\'' + 43 | ", pwd='" + pwd + '\'' + 44 | ", name='" + name + '\'' + 45 | ", email='" + email + '\'' + 46 | ", birth=" + birth + 47 | ", sns='" + sns + '\'' + 48 | ", reg_date=" + reg_date + 49 | '}'; 50 | } 51 | 52 | public String getId() { 53 | return id; 54 | } 55 | 56 | public void setId(String id) { 57 | this.id = id; 58 | } 59 | 60 | public String getPwd() { 61 | return pwd; 62 | } 63 | 64 | public void setPwd(String pwd) { 65 | this.pwd = pwd; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public void setName(String name) { 73 | this.name = name; 74 | } 75 | 76 | public String getEmail() { 77 | return email; 78 | } 79 | 80 | public void setEmail(String email) { 81 | this.email = email; 82 | } 83 | 84 | public Date getBirth() { 85 | return birth; 86 | } 87 | 88 | public void setBirth(Date birth) { 89 | this.birth = birth; 90 | } 91 | 92 | public String getSns() { 93 | return sns; 94 | } 95 | 96 | public void setSns(String sns) { 97 | this.sns = sns; 98 | } 99 | 100 | public Date getReg_date() { 101 | return reg_date; 102 | } 103 | 104 | public void setReg_date(Date reg_date) { 105 | this.reg_date = reg_date; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ch3/UserValidator.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch3; 2 | 3 | import org.springframework.validation.Errors; 4 | import org.springframework.validation.ValidationUtils; 5 | import org.springframework.validation.Validator; 6 | 7 | public class UserValidator implements Validator { 8 | @Override 9 | public boolean supports(Class clazz) { 10 | // return User.class.equals(clazz); // 검증하려는 객체가 User타입인지 확인 11 | return User.class.isAssignableFrom(clazz); // clazz가 User 또는 그 자손인지 확인 12 | } 13 | 14 | @Override 15 | public void validate(Object target, Errors errors) { 16 | System.out.println("UserValidator.validate() is called"); 17 | 18 | User user = (User)target; 19 | 20 | String id = user.getId(); 21 | 22 | // if(id==null || "".equals(id.trim())) { 23 | // errors.rejectValue("id", "required"); 24 | // } 25 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "id", "required"); 26 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "pwd", "required"); 27 | 28 | if(id==null || id.length() < 5 || id.length() > 12) { 29 | errors.rejectValue("id", "invalidLength", new String[]{"5","12"}, null); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ch3/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch3/config1.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ch3/error_message.properties: -------------------------------------------------------------------------------- 1 | required=필수 항목입니다. 2 | required.user.pwd=사용자 비밀번호는 필수 항목입니다. 3 | invalidLength.id=아이디의 길이는 {0}~{1}사이어야 합니다. 4 | -------------------------------------------------------------------------------- /ch3/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page session="false" %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | fastcampus 11 | 12 | 13 | 14 | 15 | 25 |
26 |

This is HOME

27 |

This is HOME

28 |

This is HOME

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /ch3/loginForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page import="java.net.URLDecoder" %> 4 | <%@ page session="false" %> 5 | 6 | 7 | 8 | 9 | 10 | 11 | Login 12 | 13 | 59 | 60 | 61 |
62 |

Login

63 |
64 | 65 | ${URLDecoder.decode(param.msg)} 66 | 67 |
68 | 69 | 70 | 71 | 72 |
73 | | 74 | 비밀번호 찾기 | 75 | 회원가입 76 |
77 | 101 |
102 | 103 | 104 | -------------------------------------------------------------------------------- /ch3/menu.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin : 0; 4 | padding: 0; 5 | } 6 | 7 | a { text-decoration: none; } 8 | 9 | ul { 10 | list-style-type: none; 11 | height: 48px; 12 | width: 100%; 13 | background-color: #30426E; 14 | display: flex; 15 | } 16 | 17 | ul > li { 18 | color: lightgray; 19 | height : 100%; 20 | width:90px; 21 | display:flex; 22 | align-items: center; 23 | } 24 | 25 | ul > li > a { 26 | color: lightgray; 27 | margin:auto; 28 | padding: 10px; 29 | font-size:20px; 30 | align-items: center; 31 | } 32 | 33 | ul > li > a:hover { 34 | color :white; 35 | border-bottom: 3px solid rgb(209, 209, 209); 36 | } 37 | 38 | #logo { 39 | color:white; 40 | font-size: 18px; 41 | padding-left:40px; 42 | margin-right:auto; 43 | display: flex; 44 | } 45 | -------------------------------------------------------------------------------- /ch3/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch3/readme.md -------------------------------------------------------------------------------- /ch3/registerForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=utf-8" %> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> 4 | 5 | <%@ page import="java.net.URLDecoder"%> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 73 | Register 74 | 75 | 76 | 77 | 78 |
Register
79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 | 92 | 93 | 94 |
95 | 96 |
97 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /ch3/registerInfo.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | Insert title here 8 | 9 | 10 |

id=${user.id}

11 |

pwd=${user.pwd}

12 |

name=${user.name}

13 |

email=${user.email}

14 |

birth=${user.birth}

15 |

hobby=${user.hobby}

16 |

sns=${user.sns}

17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ch3/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ch3/root-context_aop.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ch4/BoardController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.controller; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import com.fastcampus.ch4.service.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.stereotype.*; 7 | import org.springframework.ui.*; 8 | import org.springframework.web.bind.annotation.*; 9 | import org.springframework.web.servlet.mvc.support.*; 10 | 11 | import javax.servlet.http.*; 12 | import java.time.*; 13 | import java.util.*; 14 | 15 | @Controller 16 | @RequestMapping("/board") 17 | public class BoardController { 18 | @Autowired 19 | BoardService boardService; 20 | 21 | @GetMapping("/list") 22 | public String list(HttpServletRequest request) { 23 | if(!loginCheck(request)) 24 | return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 25 | 26 | return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 27 | } 28 | 29 | private boolean loginCheck(HttpServletRequest request) { 30 | // 1. 세션을 얻어서 31 | HttpSession session = request.getSession(); 32 | // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 33 | return session.getAttribute("id")!=null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /ch4/BoardController3.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.controller; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import com.fastcampus.ch4.service.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.stereotype.*; 7 | import org.springframework.ui.*; 8 | import org.springframework.web.bind.annotation.*; 9 | import org.springframework.web.servlet.mvc.support.*; 10 | 11 | import javax.servlet.http.*; 12 | import java.time.*; 13 | import java.util.*; 14 | 15 | @Controller 16 | @RequestMapping("/board") 17 | public class BoardController { 18 | @Autowired 19 | BoardService boardService; 20 | 21 | @PostMapping("/modify") 22 | public String modify(BoardDto boardDto, SearchCondition sc, RedirectAttributes rattr, Model m, HttpSession session) { 23 | String writer = (String)session.getAttribute("id"); 24 | boardDto.setWriter(writer); 25 | 26 | try { 27 | if (boardService.modify(boardDto)!= 1) 28 | throw new Exception("Modify failed."); 29 | 30 | rattr.addFlashAttribute("msg", "MOD_OK"); 31 | return "redirect:/board/list"+sc.getQueryString(); 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | m.addAttribute(boardDto); 35 | m.addAttribute("msg", "MOD_ERR"); 36 | return "board"; 37 | } 38 | } 39 | 40 | @GetMapping("/write") 41 | public String write(Model m) { 42 | m.addAttribute("mode", "new"); 43 | 44 | return "board"; 45 | } 46 | 47 | @PostMapping("/write") 48 | public String write(BoardDto boardDto, RedirectAttributes rattr, Model m, HttpSession session) { 49 | String writer = (String)session.getAttribute("id"); 50 | boardDto.setWriter(writer); 51 | 52 | try { 53 | if (boardService.write(boardDto) != 1) 54 | throw new Exception("Write failed."); 55 | 56 | rattr.addFlashAttribute("msg", "WRT_OK"); 57 | return "redirect:/board/list"; 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | m.addAttribute(boardDto); 61 | m.addAttribute("mode", "new"); 62 | m.addAttribute("msg", "WRT_ERR"); 63 | return "board"; 64 | } 65 | } 66 | 67 | @GetMapping("/read") 68 | public String read(Integer bno, SearchCondition sc, RedirectAttributes rattr, Model m) { 69 | try { 70 | BoardDto boardDto = boardService.read(bno); 71 | m.addAttribute(boardDto); 72 | } catch (Exception e) { 73 | e.printStackTrace(); 74 | rattr.addFlashAttribute("msg", "READ_ERR"); 75 | return "redirect:/board/list"+sc.getQueryString(); 76 | } 77 | 78 | return "board"; 79 | } 80 | 81 | @PostMapping("/remove") 82 | public String remove(Integer bno, SearchCondition sc, RedirectAttributes rattr, HttpSession session) { 83 | String writer = (String)session.getAttribute("id"); 84 | String msg = "DEL_OK"; 85 | 86 | try { 87 | if(boardService.remove(bno, writer)!=1) 88 | throw new Exception("Delete failed."); 89 | } catch (Exception e) { 90 | e.printStackTrace(); 91 | msg = "DEL_ERR"; 92 | } 93 | 94 | rattr.addFlashAttribute("msg", msg); 95 | return "redirect:/board/list"+sc.getQueryString(); 96 | } 97 | 98 | @GetMapping("/list") 99 | public String list(Model m, SearchCondition sc, HttpServletRequest request) { 100 | if(!loginCheck(request)) 101 | return "redirect:/login/login?toURL="+request.getRequestURL(); // 로그인을 안했으면 로그인 화면으로 이동 102 | 103 | try { 104 | int totalCnt = boardService.getSearchResultCnt(sc); 105 | m.addAttribute("totalCnt", totalCnt); 106 | 107 | PageHandler pageHandler = new PageHandler(totalCnt, sc); 108 | 109 | List list = boardService.getSearchResultPage(sc); 110 | m.addAttribute("list", list); 111 | m.addAttribute("ph", pageHandler); 112 | 113 | Instant startOfToday = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant(); 114 | m.addAttribute("startOfToday", startOfToday.toEpochMilli()); 115 | } catch (Exception e) { 116 | e.printStackTrace(); 117 | m.addAttribute("msg", "LIST_ERR"); 118 | m.addAttribute("totalCnt", 0); 119 | } 120 | 121 | return "boardList"; // 로그인을 한 상태이면, 게시판 화면으로 이동 122 | } 123 | 124 | private boolean loginCheck(HttpServletRequest request) { 125 | // 1. 세션을 얻어서(false는 session이 없어도 새로 생성하지 않는다. 반환값 null) 126 | HttpSession session = request.getSession(false); 127 | // 2. 세션에 id가 있는지 확인, 있으면 true를 반환 128 | return session!=null && session.getAttribute("id")!=null; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /ch4/BoardDao.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | 5 | import java.util.*; 6 | 7 | public interface BoardDao { 8 | BoardDto select(Integer bno) throws Exception; 9 | int delete(Integer bno, String writer) throws Exception; 10 | int insert(BoardDto dto) throws Exception; 11 | int update(BoardDto dto) throws Exception; 12 | int increaseViewCnt(Integer bno) throws Exception; 13 | 14 | List selectPage(Map map) throws Exception; 15 | List selectAll() throws Exception; 16 | int deleteAll() throws Exception; 17 | int count() throws Exception; 18 | 19 | int searchResultCnt(SearchCondition sc) throws Exception; 20 | List searchSelectPage(SearchCondition sc) throws Exception; 21 | } 22 | -------------------------------------------------------------------------------- /ch4/BoardDaoImpl.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.apache.ibatis.session.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.stereotype.*; 7 | 8 | import java.util.*; 9 | 10 | @Repository 11 | public class BoardDaoImpl implements BoardDao { 12 | @Autowired 13 | private SqlSession session; 14 | private static String namespace = "com.fastcampus.ch4.dao.BoardMapper."; 15 | 16 | public int count() throws Exception { 17 | return session.selectOne(namespace+"count"); 18 | } // T selectOne(String statement) 19 | 20 | @Override 21 | public int deleteAll() { 22 | return session.delete(namespace+"deleteAll"); 23 | } // int delete(String statement) 24 | 25 | @Override 26 | public int delete(Integer bno, String writer) throws Exception { 27 | Map map = new HashMap(); 28 | map.put("bno", bno); 29 | map.put("writer", writer); 30 | return session.delete(namespace+"delete", map); 31 | } // int delete(String statement, Object parameter) 32 | 33 | public int insert(BoardDto dto) throws Exception { 34 | return session.insert(namespace+"insert", dto); 35 | } // int insert(String statement, Object parameter) 36 | 37 | @Override 38 | public List selectAll() throws Exception { 39 | return session.selectList(namespace+"selectAll"); 40 | } // List selectList(String statement) 41 | 42 | public BoardDto select(Integer bno) throws Exception { 43 | return session.selectOne(namespace + "select", bno); 44 | } // T selectOne(String statement, Object parameter) 45 | 46 | @Override 47 | public List selectPage(Map map) throws Exception { 48 | return session.selectList(namespace+"selectPage", map); 49 | } // List selectList(String statement, Object parameter) 50 | 51 | @Override 52 | public int update(BoardDto dto) throws Exception { 53 | return session.update(namespace+"update", dto); 54 | } // int update(String statement, Object parameter) 55 | 56 | @Override 57 | public int increaseViewCnt(Integer bno) throws Exception { 58 | return session.update(namespace+"increaseViewCnt", bno); 59 | } // int update(String statement, Object parameter) 60 | 61 | @Override 62 | public int searchResultCnt(SearchCondition sc) throws Exception { 63 | System.out.println("sc in searchResultCnt() = " + sc); 64 | System.out.println("session = " + session); 65 | return session.selectOne(namespace+"searchResultCnt", sc); 66 | } // T selectOne(String statement, Object parameter) 67 | 68 | @Override 69 | public List searchSelectPage(SearchCondition sc) throws Exception { 70 | return session.selectList(namespace+"searchSelectPage", sc); 71 | } // List selectList(String statement, Object parameter) 72 | } 73 | -------------------------------------------------------------------------------- /ch4/BoardDto.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.domain; 2 | 3 | import java.util.*; 4 | 5 | public class BoardDto { 6 | private Integer bno; 7 | private String title; 8 | private String content; 9 | private String writer; 10 | private int view_cnt; 11 | private int comment_cnt; 12 | private Date reg_date; 13 | 14 | @Override 15 | public boolean equals(Object o) { 16 | if (this == o) return true; 17 | if (o == null || getClass() != o.getClass()) return false; 18 | BoardDto boardDto = (BoardDto) o; 19 | return Objects.equals(bno, boardDto.bno) && Objects.equals(title, boardDto.title) && Objects.equals(content, boardDto.content) && Objects.equals(writer, boardDto.writer); 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return Objects.hash(bno, title, content, writer); 25 | } 26 | 27 | public BoardDto() { this("","",""); } 28 | public BoardDto(String title, String content, String writer){ 29 | this.title = title; 30 | this.content = content; 31 | this.writer = writer; 32 | } 33 | 34 | public Integer getBno() { 35 | return bno; 36 | } 37 | public void setBno(Integer bno) { 38 | this.bno = bno; 39 | } 40 | public String getTitle() { 41 | return title; 42 | } 43 | public void setTitle(String title) { 44 | this.title = title; 45 | } 46 | public String getContent() { 47 | return content; 48 | } 49 | public void setContent(String content) { 50 | this.content = content; 51 | } 52 | public String getWriter() { 53 | return writer; 54 | } 55 | public void setWriter(String writer) { 56 | this.writer = writer; 57 | } 58 | public int getView_cnt() { 59 | return view_cnt; 60 | } 61 | public void setView_cnt(int view_cnt) { 62 | this.view_cnt = view_cnt; 63 | } 64 | public int getComment_cnt() { 65 | return comment_cnt; 66 | } 67 | public void setComment_cnt(int comment_cnt) { 68 | this.comment_cnt = comment_cnt; 69 | } 70 | public Date getReg_date() { 71 | return reg_date; 72 | } 73 | public void setReg_date(Date reg_date) { 74 | this.reg_date = reg_date; 75 | } 76 | 77 | @Override 78 | public String toString() { 79 | return "BoardDto{" + 80 | "bno=" + bno + 81 | ", title='" + title + '\'' + 82 | ", content='" + content + '\'' + 83 | ", writer='" + writer + '\'' + 84 | ", view_cnt=" + view_cnt + 85 | ", comment_cnt=" + comment_cnt + 86 | ", reg_date=" + reg_date + 87 | '}'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ch4/BoardService.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.service; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | 5 | import java.util.*; 6 | 7 | public interface BoardService { 8 | int getCount() throws Exception; 9 | int remove(Integer bno, String writer) throws Exception; 10 | int write(BoardDto boardDto) throws Exception; 11 | List getList() throws Exception; 12 | BoardDto read(Integer bno) throws Exception; 13 | List getPage(Map map) throws Exception; 14 | int modify(BoardDto boardDto) throws Exception; 15 | 16 | int getSearchResultCnt(SearchCondition sc) throws Exception; 17 | List getSearchResultPage(SearchCondition sc) throws Exception; 18 | } 19 | -------------------------------------------------------------------------------- /ch4/BoardServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.service; 2 | 3 | import com.fastcampus.ch4.dao.*; 4 | import com.fastcampus.ch4.domain.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.stereotype.*; 7 | 8 | import java.util.*; 9 | 10 | @Service 11 | public class BoardServiceImpl implements BoardService { 12 | @Autowired 13 | BoardDao boardDao; 14 | 15 | @Override 16 | public int getCount() throws Exception { 17 | return boardDao.count(); 18 | } 19 | 20 | @Override 21 | public int remove(Integer bno, String writer) throws Exception { 22 | return boardDao.delete(bno, writer); 23 | } 24 | 25 | @Override 26 | public int write(BoardDto boardDto) throws Exception { 27 | return boardDao.insert(boardDto); 28 | } 29 | 30 | @Override 31 | public List getList() throws Exception { 32 | return boardDao.selectAll(); 33 | } 34 | 35 | @Override 36 | public BoardDto read(Integer bno) throws Exception { 37 | BoardDto boardDto = boardDao.select(bno); 38 | boardDao.increaseViewCnt(bno); 39 | 40 | return boardDto; 41 | } 42 | 43 | @Override 44 | public List getPage(Map map) throws Exception { 45 | return boardDao.selectPage(map); 46 | } 47 | 48 | @Override 49 | public int modify(BoardDto boardDto) throws Exception { 50 | return boardDao.update(boardDto); 51 | } 52 | 53 | @Override 54 | public int getSearchResultCnt(SearchCondition sc) throws Exception { 55 | return boardDao.searchResultCnt(sc); 56 | } 57 | 58 | @Override 59 | public List getSearchResultPage(SearchCondition sc) throws Exception { 60 | return boardDao.searchSelectPage(sc); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ch4/BoardServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.service; 2 | 3 | import org.junit.*; 4 | 5 | import java.time.*; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | public class BoardServiceImplTest { 10 | 11 | @Test 12 | public void read() { 13 | } 14 | 15 | @Test 16 | public void edit() { 17 | } 18 | 19 | @Test 20 | public void write() { 21 | } 22 | 23 | @Test 24 | public void remove() { 25 | } 26 | 27 | @Test 28 | public void getPage() { 29 | } 30 | 31 | @Test 32 | public void getList() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ch4/CommentController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.controller; 2 | 3 | import com.fastcampus.ch4.domain.CommentDto; 4 | import com.fastcampus.ch4.service.CommentService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.http.ResponseEntity; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.servlet.http.HttpSession; 12 | import java.util.List; 13 | 14 | //@Controller 15 | //@ResponseBody 16 | @RestController 17 | public class CommentController { 18 | @Autowired 19 | CommentService service; 20 | 21 | // { 22 | // "pcno":0, 23 | // "comment" : "hihihi", 24 | // "commenter" : "asdf" 25 | // } 26 | // 댓글을 수정하는 메서드 27 | @PatchMapping("/comments/{cno}") // /ch4/comments/26 PATCH 28 | public ResponseEntity modify(@PathVariable Integer cno, @RequestBody CommentDto dto) { 29 | // String commenter = (String)session.getAttribute("id"); 30 | String commenter = "asdf"; 31 | dto.setCommenter(commenter); 32 | dto.setCno(cno); 33 | System.out.println("dto = " + dto); 34 | 35 | try { 36 | if(service.modify(dto)!=1) 37 | throw new Exception("Write failed."); 38 | 39 | return new ResponseEntity<>("MOD_OK", HttpStatus.OK); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | return new ResponseEntity("MOD_ERR", HttpStatus.BAD_REQUEST); 43 | } 44 | } 45 | 46 | // { 47 | // "pcno":0, 48 | // "comment" : "hi" 49 | // } 50 | // 댓글을 등록하는 메서드 51 | @PostMapping("/comments") // /ch4/comments?bno=1085 POST 52 | public ResponseEntity write(@RequestBody CommentDto dto, Integer bno, HttpSession session) { 53 | // String commenter = (String)session.getAttribute("id"); 54 | String commenter = "asdf"; 55 | dto.setCommenter(commenter); 56 | dto.setBno(bno); 57 | System.out.println("dto = " + dto); 58 | 59 | try { 60 | if(service.write(dto)!=1) 61 | throw new Exception("Write failed."); 62 | 63 | return new ResponseEntity<>("WRT_OK", HttpStatus.OK); 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | return new ResponseEntity("WRT_ERR", HttpStatus.BAD_REQUEST); 67 | } 68 | } 69 | 70 | // 지정된 댓글을 삭제하는 메서드 71 | @DeleteMapping("/comments/{cno}") // DELETE /comments/1?bno=1085 <-- 삭제할 댓글 번호 72 | public ResponseEntity remove(@PathVariable Integer cno, Integer bno, HttpSession session) { 73 | // String commenter = (String)session.getAttribute("id"); 74 | String commenter = "asdf"; 75 | 76 | try { 77 | int rowCnt = service.remove(cno, bno, commenter); 78 | 79 | if(rowCnt!=1) 80 | throw new Exception("Delete Failed"); 81 | 82 | return new ResponseEntity<>("DEL_OK", HttpStatus.OK); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | return new ResponseEntity<>("DEL_ERR", HttpStatus.BAD_REQUEST); 86 | } 87 | } 88 | 89 | // 지정된 게시물의 모든 댓글을 가져오는 메서드 90 | @GetMapping("/comments") // /comments?bno=1080 GET 91 | public ResponseEntity> list(Integer bno) { 92 | List list = null; 93 | try { 94 | list = service.getList(bno); 95 | return new ResponseEntity>(list, HttpStatus.OK); // 200 96 | } catch (Exception e) { 97 | e.printStackTrace(); 98 | return new ResponseEntity>(HttpStatus.BAD_REQUEST); // 400 99 | } 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /ch4/CommentDao.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.CommentDto; 4 | import org.apache.ibatis.annotations.Param; 5 | 6 | import java.util.List; 7 | 8 | public interface CommentDao { 9 | int count(Integer bno) throws Exception; 10 | int deleteAll(Integer bno); 11 | int delete(Integer cno, String commenter) throws Exception; 12 | int insert(CommentDto dto) throws Exception; 13 | List selectAll(Integer bno) throws Exception; 14 | CommentDto select(Integer cno) throws Exception; 15 | int update(CommentDto dto) throws Exception; 16 | } 17 | -------------------------------------------------------------------------------- /ch4/CommentDaoImpl.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.apache.ibatis.annotations.*; 5 | import org.apache.ibatis.session.*; 6 | import org.springframework.beans.factory.annotation.*; 7 | import org.springframework.stereotype.*; 8 | 9 | import java.util.*; 10 | 11 | @Repository 12 | public class CommentDaoImpl implements CommentDao { 13 | @Autowired 14 | private SqlSession session; 15 | private static String namespace = "com.fastcampus.ch4.dao.CommentMapper."; 16 | 17 | @Override 18 | public int count(Integer bno) throws Exception { 19 | return session.selectOne(namespace+"count", bno); 20 | } // T selectOne(String statement) 21 | 22 | @Override 23 | public int deleteAll(Integer bno) { 24 | return session.delete(namespace+"deleteAll", bno); 25 | } // int delete(String statement) 26 | 27 | @Override 28 | public int delete(Integer cno, String commenter) throws Exception { 29 | Map map = new HashMap(); 30 | map.put("cno", cno); 31 | map.put("commenter", commenter); 32 | return session.delete(namespace+"delete", map); 33 | } // int delete(String statement, Object parameter) 34 | 35 | @Override 36 | public int insert(CommentDto dto) throws Exception { 37 | return session.insert(namespace+"insert", dto); 38 | } // int insert(String statement, Object parameter) 39 | 40 | @Override 41 | public List selectAll(Integer bno) throws Exception { 42 | return session.selectList(namespace+"selectAll", bno); 43 | } // List selectList(String statement) 44 | 45 | @Override 46 | public CommentDto select(Integer cno) throws Exception { 47 | return session.selectOne(namespace + "select", cno); 48 | } // T selectOne(String statement, Object parameter) 49 | 50 | @Override 51 | public int update(CommentDto dto) throws Exception { 52 | return session.update(namespace+"update", dto); 53 | } // int update(String statement, Object parameter) 54 | } 55 | -------------------------------------------------------------------------------- /ch4/CommentDaoImplTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.junit.*; 5 | import org.junit.runner.*; 6 | import org.springframework.beans.factory.annotation.*; 7 | import org.springframework.test.context.*; 8 | import org.springframework.test.context.junit4.*; 9 | 10 | import java.util.*; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | @RunWith(SpringJUnit4ClassRunner.class) 15 | @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) 16 | public class CommentDaoImplTest { 17 | @Autowired 18 | CommentDao commentDao; 19 | 20 | @Test 21 | public void count() throws Exception { 22 | commentDao.deleteAll(1); 23 | assertTrue(commentDao.count(1)==0); 24 | } 25 | 26 | @Test 27 | public void delete() throws Exception { 28 | commentDao.deleteAll(1); 29 | CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); 30 | assertTrue(commentDao.insert(commentDto)==1); 31 | assertTrue(commentDao.count(1)==1); 32 | } 33 | 34 | @Test 35 | public void insert() throws Exception { 36 | commentDao.deleteAll(1); 37 | CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); 38 | assertTrue(commentDao.insert(commentDto)==1); 39 | assertTrue(commentDao.count(1)==1); 40 | 41 | commentDto = new CommentDto(1, 0, "comment", "asdf"); 42 | assertTrue(commentDao.insert(commentDto)==1); 43 | assertTrue(commentDao.count(1)==2); 44 | } 45 | 46 | @Test 47 | public void selectAll() throws Exception { 48 | commentDao.deleteAll(1); 49 | CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); 50 | assertTrue(commentDao.insert(commentDto)==1); 51 | assertTrue(commentDao.count(1)==1); 52 | 53 | List list = commentDao.selectAll(1); 54 | assertTrue(list.size()==1); 55 | 56 | commentDto = new CommentDto(1, 0, "comment", "asdf"); 57 | assertTrue(commentDao.insert(commentDto)==1); 58 | assertTrue(commentDao.count(1)==2); 59 | 60 | list = commentDao.selectAll(1); 61 | assertTrue(list.size()==2); 62 | } 63 | 64 | @Test 65 | public void select() throws Exception { 66 | commentDao.deleteAll(1); 67 | CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); 68 | assertTrue(commentDao.insert(commentDto)==1); 69 | assertTrue(commentDao.count(1)==1); 70 | 71 | List list = commentDao.selectAll(1); 72 | String comment = list.get(0).getComment(); 73 | String commenter = list.get(0).getCommenter(); 74 | assertTrue(comment.equals(commentDto.getComment())); 75 | assertTrue(commenter.equals(commentDto.getCommenter())); 76 | } 77 | 78 | @Test 79 | public void update() throws Exception { 80 | commentDao.deleteAll(1); 81 | CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf"); 82 | assertTrue(commentDao.insert(commentDto)==1); 83 | assertTrue(commentDao.count(1)==1); 84 | 85 | List list = commentDao.selectAll(1); 86 | commentDto.setCno(list.get(0).getCno()); 87 | commentDto.setComment("comment2"); 88 | assertTrue(commentDao.update(commentDto)==1); 89 | 90 | list = commentDao.selectAll(1); 91 | String comment = list.get(0).getComment(); 92 | String commenter = list.get(0).getCommenter(); 93 | assertTrue(comment.equals(commentDto.getComment())); 94 | assertTrue(commenter.equals(commentDto.getCommenter())); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ch4/CommentDto.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.domain; 2 | 3 | import java.util.*; 4 | 5 | public class CommentDto { 6 | private Integer cno; 7 | private Integer bno; 8 | private Integer pcno; 9 | private String comment; 10 | private String commenter; 11 | private Date reg_date; 12 | private Date up_date; 13 | 14 | public CommentDto() {} 15 | public CommentDto(Integer bno, Integer pcno, String comment, String commenter) { 16 | this.bno = bno; 17 | this.pcno = pcno; 18 | this.comment = comment; 19 | this.commenter = commenter; 20 | } 21 | 22 | @Override 23 | public boolean equals(Object o) { 24 | if (this == o) return true; 25 | if (o == null || getClass() != o.getClass()) return false; 26 | CommentDto that = (CommentDto) o; 27 | 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); 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | return Objects.hash(cno, bno, pcno, comment, commenter); 33 | } 34 | 35 | public Integer getBno() { 36 | return bno; 37 | } 38 | 39 | public void setBno(Integer bno) { 40 | this.bno = bno; 41 | } 42 | 43 | public Integer getPcno() { 44 | return pcno; 45 | } 46 | 47 | public void setPcno(Integer pcno) { 48 | this.pcno = pcno; 49 | } 50 | 51 | public String getComment() { 52 | return comment; 53 | } 54 | 55 | public void setComment(String comment) { 56 | this.comment = comment; 57 | } 58 | 59 | public String getCommenter() { 60 | return commenter; 61 | } 62 | 63 | public void setCommenter(String commenter) { 64 | this.commenter = commenter; 65 | } 66 | 67 | public Date getReg_date() { 68 | return reg_date; 69 | } 70 | 71 | public void setReg_date(Date reg_date) { 72 | this.reg_date = reg_date; 73 | } 74 | 75 | public Date getUp_date() { 76 | return up_date; 77 | } 78 | 79 | public void setUp_date(Date up_date) { 80 | this.up_date = up_date; 81 | } 82 | 83 | public Integer getCno() { 84 | return cno; 85 | } 86 | 87 | public void setCno(Integer cno) { 88 | this.cno = cno; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return "CommentDto{" + 94 | "cno=" + cno + 95 | ", bno=" + bno + 96 | ", pcno=" + pcno + 97 | ", comment='" + comment + '\'' + 98 | ", commenter='" + commenter + '\'' + 99 | ", reg_date=" + reg_date + 100 | ", up_date=" + up_date + 101 | '}'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ch4/CommentServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.service; 2 | 3 | import com.fastcampus.ch4.dao.*; 4 | import com.fastcampus.ch4.domain.*; 5 | import org.springframework.beans.factory.annotation.*; 6 | import org.springframework.stereotype.*; 7 | import org.springframework.transaction.annotation.*; 8 | 9 | import java.util.*; 10 | 11 | @Service 12 | public class CommentServiceImpl implements CommentService { 13 | @Autowired 14 | BoardDao boardDao; 15 | @Autowired 16 | CommentDao commentDao; 17 | 18 | // @Autowired 19 | // public CommentServiceImpl(CommentDao commentDao, BoardDao boardDao) { 20 | // this.commentDao = commentDao; 21 | // this.boardDao = boardDao; 22 | // } 23 | 24 | @Override 25 | public int getCount(Integer bno) throws Exception { 26 | return commentDao.count(bno); 27 | } 28 | 29 | @Override 30 | 31 | @Transactional(rollbackFor = Exception.class) 32 | public int remove(Integer cno, Integer bno, String commenter) throws Exception { 33 | int rowCnt = boardDao.updateCommentCnt(bno, -1); 34 | System.out.println("updateCommentCnt - rowCnt = " + rowCnt); 35 | // throw new Exception("test"); 36 | rowCnt = commentDao.delete(cno, commenter); 37 | System.out.println("rowCnt = " + rowCnt); 38 | return rowCnt; 39 | } 40 | 41 | @Override 42 | @Transactional(rollbackFor = Exception.class) 43 | public int write(CommentDto commentDto) throws Exception { 44 | boardDao.updateCommentCnt(commentDto.getBno(), 1); 45 | // throw new Exception("test"); 46 | return commentDao.insert(commentDto); 47 | } 48 | 49 | @Override 50 | public List getList(Integer bno) throws Exception { 51 | // throw new Exception("test"); 52 | return commentDao.selectAll(bno); 53 | } 54 | 55 | @Override 56 | public CommentDto read(Integer cno) throws Exception { 57 | return commentDao.select(cno); 58 | } 59 | 60 | @Override 61 | public int modify(CommentDto commentDto) throws Exception { 62 | return commentDao.update(commentDto); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ch4/CommentServiceImplTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.service; 2 | 3 | import com.fastcampus.ch4.dao.*; 4 | import com.fastcampus.ch4.domain.*; 5 | import org.junit.*; 6 | import org.junit.runner.*; 7 | import org.springframework.beans.factory.annotation.*; 8 | import org.springframework.test.context.*; 9 | import org.springframework.test.context.junit4.*; 10 | 11 | import java.util.*; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | @RunWith(SpringJUnit4ClassRunner.class) 16 | @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"}) 17 | public class CommentServiceImplTest { 18 | @Autowired 19 | CommentService commentService; 20 | @Autowired 21 | CommentDao commentDao; 22 | @Autowired 23 | BoardDao boardDao; 24 | 25 | @Test 26 | public void remove() throws Exception { 27 | boardDao.deleteAll(); 28 | 29 | BoardDto boardDto = new BoardDto("hello", "hello", "asdf"); 30 | assertTrue(boardDao.insert(boardDto) == 1); 31 | Integer bno = boardDao.selectAll().get(0).getBno(); 32 | System.out.println("bno = " + bno); 33 | 34 | commentDao.deleteAll(bno); 35 | CommentDto commentDto = new CommentDto(bno,0,"hi","qwer"); 36 | 37 | assertTrue(boardDao.select(bno).getComment_cnt() == 0); 38 | assertTrue(commentService.write(commentDto)==1); 39 | assertTrue(boardDao.select(bno).getComment_cnt() == 1); 40 | 41 | Integer cno = commentDao.selectAll(bno).get(0).getCno(); 42 | 43 | // 일부러 예외를 발생시키고 Tx가 취소되는지 확인해야. 44 | int rowCnt = commentService.remove(cno, bno, commentDto.getCommenter()); 45 | assertTrue(rowCnt==1); 46 | assertTrue(boardDao.select(bno).getComment_cnt() == 0); 47 | } 48 | 49 | @Test 50 | public void write() throws Exception { 51 | boardDao.deleteAll(); 52 | 53 | BoardDto boardDto = new BoardDto("hello", "hello", "asdf"); 54 | assertTrue(boardDao.insert(boardDto) == 1); 55 | Integer bno = boardDao.selectAll().get(0).getBno(); 56 | System.out.println("bno = " + bno); 57 | 58 | commentDao.deleteAll(bno); 59 | CommentDto commentDto = new CommentDto(bno,0,"hi","qwer"); 60 | 61 | assertTrue(boardDao.select(bno).getComment_cnt() == 0); 62 | assertTrue(commentService.write(commentDto)==1); 63 | 64 | Integer cno = commentDao.selectAll(bno).get(0).getCno(); 65 | assertTrue(boardDao.select(bno).getComment_cnt() == 1); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ch4/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.controller; 2 | 3 | import java.net.URLEncoder; 4 | 5 | import javax.servlet.http.Cookie; 6 | import javax.servlet.http.HttpServletRequest; 7 | import javax.servlet.http.HttpServletResponse; 8 | import javax.servlet.http.HttpSession; 9 | 10 | import com.fastcampus.ch4.dao.*; 11 | import com.fastcampus.ch4.domain.*; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Controller; 14 | import org.springframework.web.bind.annotation.CookieValue; 15 | import org.springframework.web.bind.annotation.GetMapping; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | 19 | @Controller 20 | @RequestMapping("/login") 21 | public class LoginController { 22 | @Autowired 23 | UserDao userDao; 24 | 25 | @GetMapping("/login") 26 | public String loginForm() { 27 | return "loginForm"; 28 | } 29 | 30 | @GetMapping("/logout") 31 | public String logout(HttpSession session) { 32 | // 1. 세션을 종료 33 | session.invalidate(); 34 | // 2. 홈으로 이동 35 | return "redirect:/"; 36 | } 37 | 38 | @PostMapping("/login") 39 | public String login(String id, String pwd, String toURL, boolean rememberId, 40 | HttpServletRequest request, HttpServletResponse response) throws Exception { 41 | 42 | // 1. id와 pwd를 확인 43 | if(!loginCheck(id, pwd)) { 44 | // 2-1 일치하지 않으면, loginForm으로 이동 45 | String msg = URLEncoder.encode("id 또는 pwd가 일치하지 않습니다.", "utf-8"); 46 | 47 | return "redirect:/login/login?msg="+msg; 48 | } 49 | // 2-2. id와 pwd가 일치하면, 50 | // 세션 객체를 얻어오기 51 | HttpSession session = request.getSession(); 52 | // 세션 객체에 id를 저장 53 | session.setAttribute("id", id); 54 | 55 | if(rememberId) { 56 | // 1. 쿠키를 생성 57 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 58 | // 2. 응답에 저장 59 | response.addCookie(cookie); 60 | } else { 61 | // 1. 쿠키를 삭제 62 | Cookie cookie = new Cookie("id", id); // ctrl+shift+o 자동 import 63 | cookie.setMaxAge(0); // 쿠키를 삭제 64 | // 2. 응답에 저장 65 | response.addCookie(cookie); 66 | } 67 | // 3. 홈으로 이동 68 | toURL = toURL==null || toURL.equals("") ? "/" : toURL; 69 | 70 | return "redirect:"+toURL; 71 | } 72 | 73 | private boolean loginCheck(String id, String pwd) { 74 | User user = null; 75 | 76 | try { 77 | user = userDao.selectUser(id); 78 | } catch (Exception e) { 79 | e.printStackTrace(); 80 | return false; 81 | } 82 | 83 | return user!=null && user.getPwd().equals(pwd); 84 | // return "asdf".equals(id) && "1234".equals(pwd); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ch4/PageHandler.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.domain; 2 | 3 | import org.springframework.web.util.*; 4 | 5 | public class PageHandler { 6 | private SearchCondition sc; 7 | // private int pageSize = 10; // 한 페이지당 게시물 갯수 8 | // private int page; // 현재 페이지 9 | // private String option; 10 | // private String keyword; 11 | public final int NAV_SIZE = 10; // page navigation size 12 | private int totalCnt; // 게시물의 총 갯수 13 | private int totalPage; // 전체 페이지의 갯수 14 | private int beginPage; // 화면에 보여줄 첫 페이지 15 | private int endPage; // 화면에 보여줄 마지막 페이지 16 | private boolean showNext = false; // 이후를 보여줄지의 여부. endPage==totalPage이면, showNext는 false 17 | private boolean showPrev = false; // 이전을 보여줄지의 여부. beginPage==1이 아니면 showPrev는 false 18 | 19 | public PageHandler(int totalCnt, Integer page) { 20 | this(totalCnt, new SearchCondition(page, 10)); 21 | } 22 | 23 | public PageHandler(int totalCnt, Integer page, Integer pageSize) { 24 | this(totalCnt, new SearchCondition(page, pageSize)); 25 | } 26 | 27 | public PageHandler(int totalCnt, SearchCondition sc) { 28 | this.totalCnt = totalCnt; 29 | this.sc = sc; 30 | 31 | doPaging(totalCnt, sc); 32 | } 33 | 34 | private void doPaging(int totalCnt, SearchCondition sc) { 35 | this.totalPage = totalCnt / sc.getPageSize() + (totalCnt % sc.getPageSize()==0? 0:1); 36 | this.sc.setPage(Math.min(sc.getPage(), totalPage)); // page가 totalPage보다 크지 않게 37 | this.beginPage = (this.sc.getPage() -1) / NAV_SIZE * NAV_SIZE + 1; // 11 -> 11, 10 -> 1, 15->11. 따로 떼어내서 테스트 38 | this.endPage = Math.min(beginPage + NAV_SIZE - 1, totalPage); 39 | this.showPrev = beginPage!=1; 40 | this.showNext = endPage!=totalPage; 41 | } 42 | 43 | public String getQueryString() { 44 | return getQueryString(this.sc.getPage()); 45 | } 46 | 47 | public String getQueryString(Integer page) { 48 | // ?page=10&pageSize=10&option=A&keyword=title 49 | return UriComponentsBuilder.newInstance() 50 | .queryParam("page", page) 51 | .queryParam("pageSize", sc.getPageSize()) 52 | .queryParam("option", sc.getOption()) 53 | .queryParam("keyword", sc.getKeyword()) 54 | .build().toString(); 55 | } 56 | 57 | void print() { 58 | System.out.println("page="+ sc.getPage()); 59 | System.out.print(showPrev? "PREV " : ""); 60 | 61 | for(int i=beginPage;i<=endPage;i++) { 62 | System.out.print(i+" "); 63 | } 64 | System.out.println(showNext? " NEXT" : ""); 65 | } 66 | 67 | public SearchCondition getSc() { 68 | return sc; 69 | } 70 | 71 | public void setSc(SearchCondition sc) { 72 | this.sc = sc; 73 | } 74 | 75 | public int getTotalCnt() { 76 | return totalCnt; 77 | } 78 | 79 | public void setTotalCnt(int totalCnt) { 80 | this.totalCnt = totalCnt; 81 | } 82 | 83 | public boolean isShowNext() { 84 | return showNext; 85 | } 86 | 87 | public void setShowNext(boolean showNext) { 88 | this.showNext = showNext; 89 | } 90 | 91 | public int getBeginPage() { 92 | return beginPage; 93 | } 94 | 95 | public void setBeginPage(int beginPage) { 96 | this.beginPage = beginPage; 97 | } 98 | 99 | public int getNAV_SIZE() { 100 | return NAV_SIZE; 101 | } 102 | 103 | public int getTotalPage() { 104 | return totalPage; 105 | } 106 | 107 | public void setTotalPage(int totalPage) { 108 | this.totalPage = totalPage; 109 | } 110 | 111 | public int getEndPage() { 112 | return endPage; 113 | } 114 | 115 | public void setEndPage(int endPage) { 116 | this.endPage = endPage; 117 | } 118 | 119 | public boolean isShowPrev() { 120 | return showPrev; 121 | } 122 | 123 | public void setShowPrev(boolean showPrev) { 124 | this.showPrev = showPrev; 125 | } 126 | 127 | @Override 128 | public String toString() { 129 | return "PageHandler{" + 130 | "sc=" + sc + 131 | ", totalCnt=" + totalCnt + 132 | ", showNext=" + showNext + 133 | ", beginPage=" + beginPage + 134 | ", NAV_SIZE=" + NAV_SIZE + 135 | ", totalPage=" + totalPage + 136 | ", endPage=" + endPage + 137 | ", showPrev=" + showPrev + 138 | '}'; 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /ch4/SearchCondition.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.domain; 2 | 3 | import org.springframework.web.util.UriComponentsBuilder; 4 | 5 | import static java.lang.Math.*; 6 | import static java.util.Objects.requireNonNullElse; 7 | 8 | public class SearchCondition { 9 | private Integer page = 1; 10 | private Integer pageSize = DEFAULT_PAGE_SIZE; 11 | private String option = ""; 12 | private String keyword = ""; 13 | // private Integer offset; 14 | 15 | public static final int MIN_PAGE_SIZE = 5; 16 | public static final int DEFAULT_PAGE_SIZE = 10; 17 | public static final int MAX_PAGE_SIZE = 50; 18 | 19 | public SearchCondition(){} 20 | 21 | public SearchCondition(Integer page, Integer pageSize) { 22 | this(page, pageSize, "", ""); 23 | } 24 | 25 | public SearchCondition(Integer page, Integer pageSize, String option, String keyword) { 26 | this.page = page; 27 | this.pageSize = pageSize; 28 | this.option = option; 29 | this.keyword = keyword; 30 | } 31 | 32 | public String getQueryString() { 33 | return getQueryString(page); 34 | } 35 | 36 | public String getQueryString(Integer page) { 37 | // ?page=10&pageSize=10&option=A&keyword=title 38 | return UriComponentsBuilder.newInstance() 39 | .queryParam("page", page) 40 | .queryParam("pageSize", pageSize) 41 | .queryParam("option", option) 42 | .queryParam("keyword", keyword) 43 | .build().toString(); 44 | } 45 | public Integer getPage() { 46 | return page; 47 | } 48 | 49 | public void setPage(Integer page) { 50 | this.page = page; 51 | } 52 | 53 | public Integer getPageSize() { 54 | return pageSize; 55 | } 56 | 57 | public void setPageSize(Integer pageSize) { 58 | this.pageSize = requireNonNullElse(pageSize, DEFAULT_PAGE_SIZE); 59 | 60 | // MIN_PAGE_SIZE <= pageSize <= MAX_PAGE_SIZE 61 | this.pageSize = max(MIN_PAGE_SIZE, min(this.pageSize, MAX_PAGE_SIZE)); 62 | } 63 | 64 | public String getOption() { 65 | return option; 66 | } 67 | 68 | public void setOption(String option) { 69 | this.option = option; 70 | } 71 | 72 | public String getKeyword() { 73 | return keyword; 74 | } 75 | 76 | public void setKeyword(String keyword) { 77 | this.keyword = keyword; 78 | } 79 | 80 | public Integer getOffset() { 81 | return (page-1)*pageSize; 82 | } 83 | 84 | @Override 85 | public String toString() { 86 | return "SearchCondition{" + 87 | "page=" + page + 88 | ", pageSize=" + pageSize + 89 | ", option='" + option + '\'' + 90 | ", keyword='" + keyword + '\'' + 91 | '}'; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /ch4/SimpleRestController.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.controller; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.springframework.stereotype.*; 5 | import org.springframework.web.bind.annotation.*; 6 | 7 | @Controller 8 | public class SimpleRestController { 9 | @GetMapping("/ajax") 10 | public String ajax() { 11 | return "ajax"; 12 | } 13 | 14 | @PostMapping("/send") 15 | @ResponseBody 16 | public Person test(@RequestBody Person p) { 17 | System.out.println("p = " + p); 18 | p.setName("ABC"); 19 | p.setAge(p.getAge() + 10); 20 | 21 | return p; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ch4/User.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.domain; 2 | 3 | import java.util.Date; 4 | import java.util.Objects; 5 | 6 | public class User { 7 | private String id; 8 | private String pwd; 9 | private String name; 10 | private String email; 11 | private Date birth; 12 | private String sns; 13 | private Date reg_date; 14 | 15 | public User(){} 16 | public User(String id, String pwd, String name, String email, Date birth, String sns, Date reg_date) { 17 | this.id = id; 18 | this.pwd = pwd; 19 | this.name = name; 20 | this.email = email; 21 | this.birth = birth; 22 | this.sns = sns; 23 | this.reg_date = reg_date; 24 | } 25 | 26 | @Override 27 | public boolean equals(Object o) { 28 | if (this == o) return true; 29 | if (o == null || getClass() != o.getClass()) return false; 30 | User user = (User) o; 31 | 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); 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | return Objects.hash(id, pwd, name, email, birth, sns, reg_date); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "User{" + 42 | "id='" + id + '\'' + 43 | ", pwd='" + pwd + '\'' + 44 | ", name='" + name + '\'' + 45 | ", email='" + email + '\'' + 46 | ", birth=" + birth + 47 | ", sns='" + sns + '\'' + 48 | ", reg_date=" + reg_date + 49 | '}'; 50 | } 51 | 52 | public String getId() { 53 | return id; 54 | } 55 | 56 | public void setId(String id) { 57 | this.id = id; 58 | } 59 | 60 | public String getPwd() { 61 | return pwd; 62 | } 63 | 64 | public void setPwd(String pwd) { 65 | this.pwd = pwd; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public void setName(String name) { 73 | this.name = name; 74 | } 75 | 76 | public String getEmail() { 77 | return email; 78 | } 79 | 80 | public void setEmail(String email) { 81 | this.email = email; 82 | } 83 | 84 | public Date getBirth() { 85 | return birth; 86 | } 87 | 88 | public void setBirth(Date birth) { 89 | this.birth = birth; 90 | } 91 | 92 | public String getSns() { 93 | return sns; 94 | } 95 | 96 | public void setSns(String sns) { 97 | this.sns = sns; 98 | } 99 | 100 | public Date getReg_date() { 101 | return reg_date; 102 | } 103 | 104 | public void setReg_date(Date reg_date) { 105 | this.reg_date = reg_date; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /ch4/UserDao.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | 5 | public interface UserDao { 6 | User selectUser(String id) throws Exception; 7 | int deleteUser(String id) throws Exception; 8 | int insertUser(User user) throws Exception; 9 | int updateUser(User user) throws Exception; 10 | int count() throws Exception; 11 | void deleteAll() throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /ch4/UserDaoImpl.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import javax.sql.DataSource; 9 | import java.sql.Connection; 10 | import java.sql.PreparedStatement; 11 | import java.sql.ResultSet; 12 | import java.sql.SQLException; 13 | import java.util.Date; 14 | 15 | @Repository 16 | public class UserDaoImpl implements UserDao { 17 | @Autowired 18 | DataSource ds; 19 | 20 | @Override 21 | public int deleteUser(String id) throws Exception { 22 | int rowCnt = 0; 23 | String sql = "DELETE FROM user_info WHERE id= ? "; 24 | 25 | try ( // try-with-resources - since jdk7 26 | Connection conn = ds.getConnection(); 27 | PreparedStatement pstmt = conn.prepareStatement(sql); 28 | ){ 29 | pstmt.setString(1, id); 30 | return pstmt.executeUpdate(); // insert, delete, update 31 | // } catch (Exception e) { 32 | // e.printStackTrace(); 33 | // throw e; 34 | } 35 | } 36 | 37 | @Override 38 | public User selectUser(String id) throws Exception { 39 | User user = null; 40 | String sql = "SELECT * FROM user_info WHERE id= ? "; 41 | 42 | try ( 43 | Connection conn = ds.getConnection(); 44 | PreparedStatement pstmt = conn.prepareStatement(sql); 45 | ResultSet rs = pstmt.executeQuery(); // select 46 | ){ 47 | pstmt.setString(1, id); 48 | 49 | if (rs.next()) { 50 | user = new User(); 51 | user.setId(rs.getString(1)); 52 | user.setPwd(rs.getString(2)); 53 | user.setName(rs.getString(3)); 54 | user.setEmail(rs.getString(4)); 55 | user.setBirth(new Date(rs.getDate(5).getTime())); 56 | user.setSns(rs.getString(6)); 57 | user.setReg_date(new Date(rs.getTimestamp(7).getTime())); 58 | } 59 | } 60 | 61 | return user; 62 | } 63 | 64 | // 사용자 정보를 user_info테이블에 저장하는 메서드 65 | @Override 66 | public int insertUser(User user) throws Exception { 67 | int rowCnt = 0; 68 | String sql = "INSERT INTO user_info VALUES (?,?,?,?,?,?, now()) "; 69 | 70 | try( 71 | Connection conn = ds.getConnection(); 72 | PreparedStatement pstmt = conn.prepareStatement(sql); // SQL Injection공격, 성능향상 73 | ){ 74 | pstmt.setString(1, user.getId()); 75 | pstmt.setString(2, user.getPwd()); 76 | pstmt.setString(3, user.getName()); 77 | pstmt.setString(4, user.getEmail()); 78 | pstmt.setDate(5, new java.sql.Date(user.getBirth().getTime())); 79 | pstmt.setString(6, user.getSns()); 80 | 81 | return pstmt.executeUpdate(); 82 | } 83 | } 84 | 85 | @Override 86 | public int updateUser(User user) throws Exception { 87 | int rowCnt = 0; 88 | 89 | String sql = "UPDATE user_info " + 90 | "SET pwd = ?, name=?, email=?, birth =?, sns=?, reg_date=? " + 91 | "WHERE id = ? "; 92 | 93 | try ( 94 | Connection conn = ds.getConnection(); 95 | PreparedStatement pstmt = conn.prepareStatement(sql); 96 | ){ 97 | pstmt.setString(1, user.getPwd()); 98 | pstmt.setString(2, user.getName()); 99 | pstmt.setString(3, user.getEmail()); 100 | pstmt.setDate(4, new java.sql.Date(user.getBirth().getTime())); 101 | pstmt.setString(5, user.getSns()); 102 | pstmt.setTimestamp(6, new java.sql.Timestamp(user.getReg_date().getTime())); 103 | pstmt.setString(7, user.getId()); 104 | 105 | rowCnt = pstmt.executeUpdate(); 106 | } 107 | 108 | return rowCnt; 109 | } 110 | 111 | @Override 112 | public int count() throws Exception { 113 | String sql = "SELECT count(*) FROM user_info "; 114 | 115 | try( 116 | Connection conn = ds.getConnection(); 117 | PreparedStatement pstmt = conn.prepareStatement(sql); 118 | ResultSet rs = pstmt.executeQuery(); 119 | ){ 120 | rs.next(); 121 | int result = rs.getInt(1); 122 | 123 | return result; 124 | } 125 | } 126 | 127 | @Override 128 | public void deleteAll() throws Exception { 129 | try (Connection conn = ds.getConnection();) 130 | { 131 | String sql = "DELETE FROM user_info "; 132 | PreparedStatement pstmt = conn.prepareStatement(sql); 133 | pstmt.executeUpdate(); 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /ch4/UserDaoImplTest.java: -------------------------------------------------------------------------------- 1 | package com.fastcampus.ch4.dao; 2 | 3 | import com.fastcampus.ch4.domain.*; 4 | import org.junit.*; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.test.context.ContextConfiguration; 8 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 | 10 | import java.util.Calendar; 11 | import java.util.Date; 12 | 13 | import static org.junit.Assert.*; 14 | 15 | @RunWith(SpringJUnit4ClassRunner.class) 16 | @ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/**/root-context.xml"}) 17 | public class UserDaoImplTest { 18 | @Autowired 19 | UserDao userDao; 20 | Calendar cal; 21 | 22 | @Before // 각 테스트가 수행되기 직전에 이 메서드가 실행된다. 23 | public void init() { 24 | cal = Calendar.getInstance(); 25 | cal.clear(); 26 | cal.set(2021, 1, 1); 27 | } 28 | 29 | @Test(expected = Exception.class) // 예외가 발생해야 테스트 통과 30 | public void insertUser() throws Exception { 31 | userDao.deleteAll(); 32 | assertTrue(userDao.count()==0); 33 | 34 | User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); 35 | assertTrue(userDao.insertUser(user)==1); 36 | assertTrue(userDao.count()==1); 37 | 38 | User user2 = userDao.selectUser(user.getId()); 39 | assertTrue(user.equals(user2)); 40 | 41 | User user3 = new User("asdf222", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); 42 | assertTrue(userDao.insertUser(user3)==1); 43 | assertTrue(userDao.count()==2); 44 | 45 | // 같은 데이터를 2번 입력하고 예외가 발생하는지 테스트 46 | userDao.insertUser(user); // java.sql.SQLIntegrityConstraintViolationException예외발생. Duplicate entry 'asdf' for key 'PRIMARY' 47 | } 48 | 49 | @Test 50 | public void deleteUser() throws Exception { 51 | userDao.deleteAll(); 52 | assertTrue(userDao.count()==0); 53 | 54 | User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); 55 | assertTrue(userDao.insertUser(user)==1); 56 | assertTrue(userDao.count()==1); 57 | 58 | User user2 = userDao.selectUser(user.getId()); 59 | assertTrue(user.equals(user2)); 60 | assertTrue(userDao.deleteUser(user.getId())==1); 61 | 62 | user = userDao.selectUser("asdf"); 63 | assertTrue(user==null); 64 | assertTrue(userDao.count()==0); 65 | } 66 | 67 | @Test 68 | public void selectUser() throws Exception { 69 | userDao.deleteAll(); 70 | assertTrue(userDao.count()==0); 71 | 72 | User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); 73 | assertTrue(userDao.insertUser(user)==1); 74 | 75 | User user2 = userDao.selectUser(user.getId()); 76 | assertTrue(user.equals(user2)); 77 | 78 | user2 = userDao.selectUser("aaaaaaa"); 79 | assertTrue(user2==null); 80 | } 81 | 82 | @Test 83 | public void updateUser() throws Exception { 84 | userDao.deleteAll(); 85 | User user = new User("asdf", "1234", "abc", "aaa@aaa.com", new Date(cal.getTimeInMillis()), "fb", new Date()); 86 | int rowCnt = userDao.insertUser(user); 87 | assertTrue(rowCnt==1); 88 | 89 | user.setPwd("4321"); 90 | user.setEmail("bbb@bbb.com"); 91 | rowCnt = userDao.updateUser(user); 92 | assertTrue(rowCnt==1); 93 | 94 | User user2 = userDao.selectUser(user.getId()); 95 | System.out.println("user = " + user); 96 | System.out.println("user2 = " + user2); 97 | assertTrue(user.equals(user2)); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /ch4/ajax.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | 3 | 4 | Title 5 | 6 | 7 | 8 |

{name:"abc", age:10}

9 | 10 |

Data From Server :

11 |
12 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ch4/boardList.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | 4 | 5 | 6 | 7 | 8 | fastcampus 9 | 10 | 11 | 12 |
22 |

This is BOARD

23 |

This is BOARD

24 |

This is BOARD

25 |

This is BOARD

26 |

This is BOARD

27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /ch4/boardMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 11 | DELETE FROM board 12 | 13 | 14 | 15 | DELETE FROM board WHERE bno = #{bno} and writer = #{writer} 16 | 17 | 18 | 19 | INSERT INTO board 20 | (title, content, writer) 21 | VALUES 22 | (#{title}, #{content}, #{writer}) 23 | 24 | 25 | 30 | 31 | 32 | SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date 33 | FROM board 34 | 35 | 36 | 40 | 41 | 46 | 47 | 48 | UPDATE board 49 | SET title = #{title} 50 | , content = #{content} 51 | , up_date = now() 52 | WHERE bno = #{bno} 53 | 54 | 55 | 56 | UPDATE board 57 | SET comment_cnt = comment_cnt + #{cnt} 58 | WHERE bno = #{bno} 59 | 60 | 61 | 62 | UPDATE board 63 | SET view_cnt = view_cnt + 1 64 | WHERE bno = #{bno} 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ch4/boardMapper2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | 11 | DELETE FROM board 12 | 13 | 14 | 15 | DELETE FROM board WHERE bno = #{bno} and writer = #{writer} 16 | 17 | 18 | 19 | INSERT INTO board 20 | (title, content, writer) 21 | VALUES 22 | (#{title}, #{content}, #{writer}) 23 | 24 | 25 | 30 | 31 | 32 | SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date 33 | FROM board 34 | 35 | 36 | 40 | 41 | 46 | 47 | 48 | UPDATE board 49 | SET title = #{title} 50 | , content = #{content} 51 | , up_date = now() 52 | WHERE bno = #{bno} 53 | 54 | 55 | 56 | UPDATE board 57 | SET comment_cnt = comment_cnt + #{cnt} 58 | WHERE bno = #{bno} 59 | 60 | 61 | 62 | UPDATE board 63 | SET view_cnt = view_cnt + 1 64 | WHERE bno = #{bno} 65 | 66 | 67 | 68 | 69 | 70 | AND title LIKE concat('%', #{keyword}, '%') 71 | 72 | 73 | AND writer LIKE concat('%', #{keyword}, '%') 74 | 75 | 76 | AND (title LIKE concat('%', #{keyword}, '%') 77 | OR content LIKE concat('%', #{keyword}, '%')) 78 | 79 | 80 | 81 | 82 | 90 | 91 | 97 | 98 | -------------------------------------------------------------------------------- /ch4/commentMapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | DELETE FROM comment 8 | WHERE bno = #{bno} 9 | 10 | 11 | 15 | 16 | 17 | DELETE FROM comment WHERE cno = #{cno} AND commenter = #{commenter} 18 | 19 | 20 | 21 | INSERT INTO comment 22 | (bno, pcno, comment, commenter, reg_date, up_date) 23 | VALUES 24 | (#{bno}, #{pcno}, #{comment}, #{commenter}, now(), now()) 25 | 26 | 27 | 33 | 34 | 39 | 40 | 41 | UPDATE comment 42 | SET comment = #{comment} 43 | , up_date = now() 44 | WHERE cno = #{cno} and commenter = #{commenter} 45 | 46 | 47 | -------------------------------------------------------------------------------- /ch4/create_table_board.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `board` ( 2 | `bno` int(11) NOT NULL AUTO_INCREMENT, 3 | `title` varchar(45) NOT NULL, 4 | `content` text NOT NULL, 5 | `writer` varchar(30) DEFAULT NULL, 6 | `view_cnt` int(11) DEFAULT '0', 7 | `comment_cnt` int(11) DEFAULT '0', 8 | `reg_date` datetime DEFAULT CURRENT_TIMESTAMP, 9 | `up_date` datetime DEFAULT CURRENT_TIMESTAMP, 10 | PRIMARY KEY (`bno`) 11 | ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; 12 | -------------------------------------------------------------------------------- /ch4/index.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page session="false"%> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | fastcampus 12 | 13 | 14 | 15 | 16 | 26 |
27 |

This is HOME

28 |

This is HOME

29 |

This is HOME

30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /ch4/log4jdbc.log4j2.properties: -------------------------------------------------------------------------------- 1 | log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator 2 | -------------------------------------------------------------------------------- /ch4/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ch4/loginForm.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 | <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 3 | <%@ page session="false"%> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | fastcampus 12 | 13 | 14 | 60 | 61 | 62 | 72 |
" method="post" onsubmit="return formCheck(this);"> 73 |

Login

74 |
75 | 76 | ${URLDecoder.decode(param.msg)} 77 | 78 |
79 | 80 | 81 | 82 | 83 |
84 | | 85 | 비밀번호 찾기 | 86 | 회원가입 87 |
88 | 108 |
109 | 110 | 111 | -------------------------------------------------------------------------------- /ch4/menu.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin : 0; 4 | padding: 0; 5 | } 6 | 7 | a { text-decoration: none; } 8 | 9 | ul { 10 | list-style-type: none; 11 | height: 48px; 12 | width: 100%; 13 | background-color: #30426E; 14 | display: flex; 15 | } 16 | 17 | ul > li { 18 | color: lightgray; 19 | height : 100%; 20 | width:90px; 21 | display:flex; 22 | align-items: center; 23 | } 24 | 25 | ul > li > a { 26 | color: lightgray; 27 | margin:auto; 28 | padding: 10px; 29 | font-size:20px; 30 | align-items: center; 31 | } 32 | 33 | ul > li > a:hover { 34 | color :white; 35 | border-bottom: 3px solid rgb(209, 209, 209); 36 | } 37 | 38 | #logo { 39 | color:white; 40 | font-size: 18px; 41 | padding-left:40px; 42 | margin-right:auto; 43 | display: flex; 44 | } 45 | -------------------------------------------------------------------------------- /ch4/mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ch4/readme.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch4/readme.md -------------------------------------------------------------------------------- /ch4/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ch4/servlet-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ch4/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | contextConfigLocation 9 | /WEB-INF/spring/root-context.xml 10 | 11 | 12 | 13 | 14 | org.springframework.web.context.ContextLoaderListener 15 | 16 | 17 | 18 | 19 | appServlet 20 | org.springframework.web.servlet.DispatcherServlet 21 | 22 | contextConfigLocation 23 | /WEB-INF/spring/appServlet/servlet-context.xml 24 | 25 | 1 26 | 27 | 28 | 29 | appServlet 30 | / 31 | 32 | 33 | 34 | encodingFilter 35 | org.springframework.web.filter.CharacterEncodingFilter 36 | 37 | encoding 38 | UTF-8 39 | 40 | 41 | forceEncoding 42 | true 43 | 44 | 45 | 46 | 47 | encodingFilter 48 | /* 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /ch5/readme.md: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /ch5/springbasic.mwb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch5/springbasic.mwb -------------------------------------------------------------------------------- /ch5/프로젝트_파일목록.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch5/프로젝트_파일목록.xlsx -------------------------------------------------------------------------------- /ch5/화면정의서_샘플.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch5/화면정의서_샘플.pptx -------------------------------------------------------------------------------- /ch5/화면정의서_샘플_주주마켓.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch5/화면정의서_샘플_주주마켓.pdf -------------------------------------------------------------------------------- /ch5/화면정의서_요소.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/ch5/화면정의서_요소.pptx -------------------------------------------------------------------------------- /download/MySQL57설치방법_MacOS_m1.md: -------------------------------------------------------------------------------- 1 | ## MySQL8.x버전을 M1칩 Mac에 설치하는 방법 2 | 3 | 아래의 링크를 클릭하세요. 4 | 5 | https://codechobo.tistory.com/31 6 | -------------------------------------------------------------------------------- /download/ch2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch2.zip -------------------------------------------------------------------------------- /download/ch2_final.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch2_final.zip -------------------------------------------------------------------------------- /download/ch2_final_mac.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch2_final_mac.zip -------------------------------------------------------------------------------- /download/ch3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch3.zip -------------------------------------------------------------------------------- /download/ch3_final.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch3_final.zip -------------------------------------------------------------------------------- /download/ch4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/ch4.zip -------------------------------------------------------------------------------- /download/firstSpring.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/firstSpring.zip -------------------------------------------------------------------------------- /download/myportfolio.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/myportfolio.zip -------------------------------------------------------------------------------- /download/project_import1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/project_import1.PNG -------------------------------------------------------------------------------- /download/project_import2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/project_import2.PNG -------------------------------------------------------------------------------- /download/readme.md: -------------------------------------------------------------------------------- 1 | # 강의와 관련된 파일입니다. 2 | - firstSpring.zip - STS3에서 Spring MVC프로젝트가 생성되지 않는 분들은 다운받아서 import하세요. 3 | STS3메뉴에서 File > Import에서 General > Existing Projects into Workspace클릭후, Next클릭(project_import1.PNG) 4 | Select archive file클릭하고, 옆의 Browse버튼 클릭해서 firstSpring.zip이 저장된 폴더를 지정하고, Finish클릭.(project_import2.PNG) 5 | - ch2.zip - ch2강의 시작할 때 생성하는 ch2프로젝트 파일. STS3에서 Spring MVC프로젝트가 생성되지 않는 분들은 다운받아서 import하세요. 6 | firstSpring.zip과 같은 방법으로 import하시면 됩니다. 7 | - ch2_final.zip - ch2강의에서 작성한 프로젝트의 최종 버전. 위와 같은 방법으로 import하세요. 8 | 9 | -------------------------------------------------------------------------------- /download/프로젝트_파일목록.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/프로젝트_파일목록.xlsx -------------------------------------------------------------------------------- /download/화면정의서_샘플.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/화면정의서_샘플.pptx -------------------------------------------------------------------------------- /download/화면정의서_샘플_주주마켓.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/화면정의서_샘플_주주마켓.pdf -------------------------------------------------------------------------------- /download/화면정의서_요소.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/화면정의서_요소.pptx -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_01_원격실행.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_01_원격실행.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_02_HTTP요청과응답_실습.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_02_HTTP요청과응답_실습.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_03_HTTP클라이언트서버.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_03_HTTP클라이언트서버.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_04_HTTP요청과응답_이론.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_04_HTTP요청과응답_이론.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_05_SpringMVC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_05_SpringMVC.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_06_Servlet_JSP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_06_Servlet_JSP.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_07_RequestParam_ModelAttribute.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_07_RequestParam_ModelAttribute.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_08_redirect와forward.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_08_redirect와forward.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_09_RequestMapping.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_09_RequestMapping.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_10_쿠키.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_10_쿠키.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_11_세션.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_11_세션.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_12_예외처리.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_12_예외처리.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_13_DispatcherServlet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_13_DispatcherServlet.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch2_14_데이터의변환과검증.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch2_14_데이터의변환과검증.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_1_스프링DI_흉내내기1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_1_스프링DI_흉내내기1.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_2_스프링DI_활용하기_이론1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_2_스프링DI_활용하기_이론1.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_3_DAO의작성과적용.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_3_DAO의작성과적용.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_4_Transaction_commit_rollback.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_4_Transaction_commit_rollback.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_5_AOP의개념과용어.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_5_AOP의개념과용어.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch3_6_서비스계층의분리와Transactional.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch3_6_서비스계층의분리와Transactional.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_01_MyBatis의개요와설정.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_01_MyBatis의개요와설정.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_02_MyBatis로DAO작성하기.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_02_MyBatis로DAO작성하기.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_03_게시판목록만들기와페이징TDD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_03_게시판목록만들기와페이징TDD.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_04_게시판CRUD기능구현1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_04_게시판CRUD기능구현1.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_05_게시판검색기능추가.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_05_게시판검색기능추가.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_06_REST_API와Ajax.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_06_REST_API와Ajax.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch4_07_댓글기능구현1_DAO작성.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch4_07_댓글기능구현1_DAO작성.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch5_01_02_git의기본명령어와원리1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch5_01_02_git의기본명령어와원리1.pdf -------------------------------------------------------------------------------- /download/강의자료/[스프링의정석_기초편]ch5_03_git의기본명령어와원리2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castello/spring_basic/5f6f2a077ff25410619a52c35348cbbf21454f8c/download/강의자료/[스프링의정석_기초편]ch5_03_git의기본명령어와원리2.pdf -------------------------------------------------------------------------------- /download/강의자료/readme.md: -------------------------------------------------------------------------------- 1 | # 강의자료입니다. 2 | -------------------------------------------------------------------------------- /download/인텔리제이_단축키.md: -------------------------------------------------------------------------------- 1 | # 인텔리제이 단축키 목록 2 | --------------------------------------------------------------------------------