Skip to content

Commit 470298c

Browse files
authored
[MVC 구현하기 - 1단계] 포츈(정윤성) 미션 제출합니다. (#42)
* test: Junit3 학습테스트 (특정 메소드명만 구동) * test: ReflectionTest 학습테스트 * test: Annotation 기반 리플랙션 학습테스트 * feat: 리플랙션을 이용해 컨트롤러 어노테이션이 붙은 클래스를 찾는 기능구현 * feat: 어노테이션 기반의 MVC 프레임워크 구현 * refactor: 사용되지 않는 메소드 삭제 * feat: jspView 구현 * feat: HandlerMapping 인터페이스 적용 * feat: 요구사항 충족을 위해 TestController 추가 * chore: sonarCube 설정 추가 * refactor: 사용되지 않는 부분들 제거 * refactor: 테스트 코드 수정 * refactor: 불필요한 로거 삭제, 로거 위치 수정
1 parent 2dc0c39 commit 470298c

27 files changed

+534
-124
lines changed

app/src/main/java/com/techcourse/AppWebApplicationInitializer.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@
33
import jakarta.servlet.ServletContext;
44
import jakarta.servlet.ServletRegistration;
55
import nextstep.mvc.DispatcherServlet;
6+
import nextstep.mvc.controller.tobe.AnnotationHandlerMapping;
67
import nextstep.web.WebApplicationInitializer;
78
import org.slf4j.Logger;
89
import org.slf4j.LoggerFactory;
910

1011
public class AppWebApplicationInitializer implements WebApplicationInitializer {
1112

12-
private static final Logger log = LoggerFactory.getLogger(AppWebApplicationInitializer.class);
13+
private static final Logger LOGGER = LoggerFactory.getLogger(AppWebApplicationInitializer.class);
14+
private static final String BASE_PACKAGE = "com.techcourse";
1315

1416
@Override
1517
public void onStartup(ServletContext servletContext) {
1618
final DispatcherServlet dispatcherServlet = new DispatcherServlet();
1719
dispatcherServlet.addHandlerMapping(new ManualHandlerMapping());
20+
dispatcherServlet.addHandlerMapping(new AnnotationHandlerMapping(BASE_PACKAGE));
1821

1922
final ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", dispatcherServlet);
2023
dispatcher.setLoadOnStartup(1);
2124
dispatcher.addMapping("/");
2225

23-
log.info("Start AppWebApplication Initializer");
26+
LOGGER.info("Start AppWebApplication Initializer");
2427
}
2528
}

app/src/main/java/com/techcourse/ManualHandlerMapping.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ public void initialize() {
2323
controllers.put("/login", new LoginController());
2424
controllers.put("/login/view", new LoginViewController());
2525
controllers.put("/logout", new LogoutController());
26-
controllers.put("/register/view", new RegisterViewController());
27-
controllers.put("/register", new RegisterController());
2826

2927
log.info("Initialized Handler Mapping!");
3028
controllers.keySet().forEach(path -> log.info("Path : {}, Controller : {}", path, controllers.get(path).getClass()));

app/src/main/java/com/techcourse/controller/LoginController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class LoginController implements Controller {
1414
private static final Logger log = LoggerFactory.getLogger(LoginController.class);
1515

1616
@Override
17-
public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
17+
public String execute(HttpServletRequest req, HttpServletResponse res) {
1818
if (UserSession.isLoggedIn(req.getSession())) {
1919
return "redirect:/index.jsp";
2020
}

app/src/main/java/com/techcourse/controller/LoginViewController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class LoginViewController implements Controller {
1111
private static final Logger log = LoggerFactory.getLogger(LoginViewController.class);
1212

1313
@Override
14-
public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
14+
public String execute(HttpServletRequest req, HttpServletResponse res) {
1515
return UserSession.getUserFrom(req.getSession())
1616
.map(user -> {
1717
log.info("logged in {}", user.getAccount());
Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,32 @@
11
package com.techcourse.controller;
22

3+
34
import com.techcourse.domain.User;
45
import com.techcourse.repository.InMemoryUserRepository;
56
import jakarta.servlet.http.HttpServletRequest;
67
import jakarta.servlet.http.HttpServletResponse;
7-
import nextstep.mvc.controller.asis.Controller;
8-
9-
public class RegisterController implements Controller {
8+
import nextstep.mvc.view.JspView;
9+
import nextstep.mvc.view.ModelAndView;
10+
import nextstep.web.annotation.Controller;
11+
import nextstep.web.annotation.RequestMapping;
12+
import nextstep.web.support.RequestMethod;
1013

11-
@Override
12-
public String execute(HttpServletRequest req, HttpServletResponse res) throws Exception {
13-
final User user = new User(2,
14-
req.getParameter("account"),
15-
req.getParameter("password"),
16-
req.getParameter("email"));
14+
@Controller
15+
public class RegisterController {
16+
17+
@RequestMapping(value = "/register", method = RequestMethod.POST)
18+
public ModelAndView save(final HttpServletRequest req, final HttpServletResponse res) {
19+
User user = new User(2,
20+
req.getParameter("account"),
21+
req.getParameter("password"),
22+
req.getParameter("email"));
1723
InMemoryUserRepository.save(user);
1824

19-
return "redirect:/index.jsp";
25+
return new ModelAndView(new JspView("redirect:/index.jsp"));
26+
}
27+
28+
@RequestMapping(value = "/register/view", method = RequestMethod.GET)
29+
public ModelAndView show(final HttpServletRequest req, final HttpServletResponse res) {
30+
return new ModelAndView(new JspView("/register.jsp"));
2031
}
21-
}
32+
}

app/src/main/java/com/techcourse/controller/RegisterViewController.java

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.techcourse.controller;
2+
3+
import jakarta.servlet.http.HttpServletRequest;
4+
import jakarta.servlet.http.HttpServletResponse;
5+
import nextstep.mvc.view.JspView;
6+
import nextstep.mvc.view.ModelAndView;
7+
import nextstep.web.annotation.Controller;
8+
import nextstep.web.annotation.RequestMapping;
9+
import nextstep.web.support.RequestMethod;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
@Controller
14+
public class TestController {
15+
16+
private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
17+
18+
@RequestMapping(value = "/get-test", method = RequestMethod.GET)
19+
public ModelAndView findUserId(final HttpServletRequest request, final HttpServletResponse response) {
20+
LOGGER.info("test controller get method");
21+
ModelAndView modelAndView = new ModelAndView(new JspView("/get-test.jsp"));
22+
modelAndView.addObject("id", request.getAttribute("id"));
23+
return modelAndView;
24+
}
25+
26+
@RequestMapping(value = "/post-test", method = RequestMethod.POST)
27+
public ModelAndView save(final HttpServletRequest request, final HttpServletResponse response) {
28+
LOGGER.info("test controller post method");
29+
ModelAndView modelAndView = new ModelAndView(new JspView("/post-test.jsp"));
30+
modelAndView.addObject("id", request.getAttribute("id"));
31+
return modelAndView;
32+
}
33+
}

app/src/main/java/com/techcourse/support/web/filter/CharacterEncodingFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class CharacterEncodingFilter implements Filter {
1111
private static final String DEFAULT_ENCODING = "UTF-8";
1212

1313
@Override
14-
public void init(FilterConfig filterConfig) throws ServletException {
14+
public void init(FilterConfig filterConfig) {
1515
}
1616

1717
@Override

app/src/main/java/com/techcourse/support/web/filter/ResourceFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class ResourceFilter implements Filter {
3232
private RequestDispatcher requestDispatcher;
3333

3434
@Override
35-
public void init(FilterConfig filterConfig) throws ServletException {
35+
public void init(FilterConfig filterConfig) {
3636
this.requestDispatcher = filterConfig.getServletContext().getNamedDispatcher("default");
3737
}
3838

app/webapp/get-test.jsp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<%@ page contentType="text/html;charset=UTF-8" %>
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<%@ include file="include/header.jspf" %>
6+
<title>404 Error - SB Admin</title>
7+
</head>
8+
<body>
9+
<div id="layoutError">
10+
<div id="layoutError_content">
11+
<main>
12+
<div class="container">
13+
<div class="row justify-content-center">
14+
<div class="col-lg-6">
15+
<div class="text-center mt-4">
16+
<h1 class="display-1">get-test</h1>
17+
<p class="lead">get-test</p>
18+
<p>get-test-Success.</p>
19+
<a href="/index.jsp">
20+
<i class="fas fa-arrow-left me-1"></i>
21+
Return to Dashboard
22+
</a>
23+
</div>
24+
</div>
25+
</div>
26+
</div>
27+
</main>
28+
</div>
29+
<div id="layoutError_footer">
30+
<footer class="py-4 bg-light mt-auto">
31+
<div class="container-fluid px-4">
32+
<div class="d-flex align-items-center justify-content-between small">
33+
<div class="text-muted">Copyright &copy; Your Website 2021</div>
34+
<div>
35+
<a href="#">Privacy Policy</a>
36+
&middot;
37+
<a href="#">Terms &amp; Conditions</a>
38+
</div>
39+
</div>
40+
</div>
41+
</footer>
42+
</div>
43+
</div>
44+
<%@ include file="include/footer.jspf" %>
45+
</body>
46+
</html>

app/webapp/post-test.jsp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<%@ page contentType="text/html;charset=UTF-8" %>
2+
<!DOCTYPE html>
3+
<html lang="en">
4+
<head>
5+
<%@ include file="include/header.jspf" %>
6+
<title>404 Error - SB Admin</title>
7+
</head>
8+
<body>
9+
<div id="layoutError">
10+
<div id="layoutError_content">
11+
<main>
12+
<div class="container">
13+
<div class="row justify-content-center">
14+
<div class="col-lg-6">
15+
<div class="text-center mt-4">
16+
<h1 class="display-1">post-test</h1>
17+
<p class="lead">post-test</p>
18+
<p>post-test-Success.</p>
19+
<a href="/index.jsp">
20+
<i class="fas fa-arrow-left me-1"></i>
21+
Return to Dashboard
22+
</a>
23+
</div>
24+
</div>
25+
</div>
26+
</div>
27+
</main>
28+
</div>
29+
<div id="layoutError_footer">
30+
<footer class="py-4 bg-light mt-auto">
31+
<div class="container-fluid px-4">
32+
<div class="d-flex align-items-center justify-content-between small">
33+
<div class="text-muted">Copyright &copy; Your Website 2021</div>
34+
<div>
35+
<a href="#">Privacy Policy</a>
36+
&middot;
37+
<a href="#">Terms &amp; Conditions</a>
38+
</div>
39+
</div>
40+
</div>
41+
</footer>
42+
</div>
43+
</div>
44+
<%@ include file="include/footer.jspf" %>
45+
</body>
46+
</html>
Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,56 @@
11
package reflection;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.lang.reflect.Method;
36
import org.junit.jupiter.api.Test;
47

5-
class Junit3TestRunner {
8+
class Junit3TestRunner extends JunitOutput {
69

710
@Test
811
void run() throws Exception {
12+
13+
//given
914
Class<Junit3Test> clazz = Junit3Test.class;
1015

1116
// TODO Junit3Test에서 test로 시작하는 메소드 실행
17+
Junit3Test junit3Test = clazz.getDeclaredConstructor().newInstance();
18+
Method[] methods = clazz.getDeclaredMethods();
19+
20+
// when
21+
for (Method method : methods) {
22+
if (method.getName().startsWith("test")) {
23+
method.invoke(junit3Test);
24+
}
25+
}
26+
String output = captor.toString().trim();
27+
28+
// then
29+
assertThat(output).contains("Running Test1");
30+
assertThat(output).contains("Running Test2");
31+
assertThat(output).doesNotContain("Running Test3");
32+
}
33+
34+
@Test
35+
void run2() throws Exception {
36+
37+
//given
38+
Class<?> clazz = Class.forName("reflection.Junit3Test");
39+
40+
Object junit3Test = clazz.getDeclaredConstructor().newInstance();
41+
Method[] methods = clazz.getDeclaredMethods();
42+
43+
// when
44+
for (Method method : methods) {
45+
if (method.getName().startsWith("test")) {
46+
method.invoke(junit3Test);
47+
}
48+
}
49+
String output = captor.toString().trim();
50+
51+
// then
52+
assertThat(output).contains("Running Test1");
53+
assertThat(output).contains("Running Test2");
54+
assertThat(output).doesNotContain("Running Test3");
1255
}
1356
}
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
package reflection;
22

3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.lang.reflect.Method;
36
import org.junit.jupiter.api.Test;
47

5-
class Junit4TestRunner {
8+
class Junit4TestRunner extends JunitOutput {
69

710
@Test
811
void run() throws Exception {
912
Class<Junit4Test> clazz = Junit4Test.class;
1013

1114
// TODO Junit4Test에서 @MyTest 애노테이션이 있는 메소드 실행
15+
Junit4Test junit4Test = clazz.getDeclaredConstructor().newInstance();
16+
Method[] methods = clazz.getDeclaredMethods();
17+
18+
for (Method method : methods) {
19+
if (method.isAnnotationPresent(MyTest.class)) {
20+
method.invoke(junit4Test);
21+
}
22+
}
23+
24+
String output = captor.toString().trim();
25+
26+
// then
27+
assertThat(output).contains("Running Test1");
28+
assertThat(output).contains("Running Test2");
29+
assertThat(output).doesNotContain("Running Test3");
1230
}
1331
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package reflection;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.OutputStream;
5+
import java.io.PrintStream;
6+
import org.junit.jupiter.api.BeforeEach;
7+
8+
public class JunitOutput {
9+
protected OutputStream captor;
10+
11+
@BeforeEach
12+
void setUp() {
13+
captor = new ByteArrayOutputStream();
14+
System.setOut(new PrintStream(captor));
15+
}
16+
}

0 commit comments

Comments
 (0)