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