Skip to content

Commit da63885

Browse files
authored
Merge pull request #12 from bobocode-projects/GP-82_dispatcher-servlet-initializer_exercise_MAIN
Gp 82 dispatcher servlet initializer exercise main
2 parents 41c43e5 + 616f2d8 commit da63885

File tree

13 files changed

+381
-0
lines changed

13 files changed

+381
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# <img src="https://raw.githubusercontent.com/bobocode-projects/resources/master/image/logo_transparent_background.png" height=50/>Hello Spring MVC exercise
2+
Improve your *Spring MVC* configuration skills 💪
3+
### Task
4+
The task is to **configure a typical *Spring MVC* application** separating web and root configs. Your job is to follow
5+
the instructions in the *todo* section and **implement a proper configuration.**
6+
7+
To verify your configuration, run `WelcomeWebAppTest.java`
8+
9+
10+
### Pre-conditions ❗
11+
You're supposed to be familiar with *Spring MVC*
12+
13+
### How to start ❓
14+
* Just clone the repository and start implementing the **todo** section, verify your changes by running tests
15+
* If you don't have enough knowledge about this domain, check out the [links below](#Related-materials-ℹ)
16+
* Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation
17+
18+
### Related materials ℹ
19+
todo
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>3-0-spring-framework</artifactId>
7+
<groupId>com.bobocode</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>3-1-1-dispatcher-servlet-initializer</artifactId>
13+
<packaging>war</packaging>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>org.springframework</groupId>
18+
<artifactId>spring-webmvc</artifactId>
19+
<version>5.2.12.RELEASE</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>javax.servlet</groupId>
23+
<artifactId>javax.servlet-api</artifactId>
24+
<version>4.0.1</version>
25+
<scope>provided</scope>
26+
</dependency>
27+
<dependency>
28+
<groupId>com.bobocode</groupId>
29+
<artifactId>java-web-util</artifactId>
30+
<version>1.0-SNAPSHOT</version>
31+
<scope>compile</scope>
32+
</dependency>
33+
</dependencies>
34+
35+
<build>
36+
<plugins>
37+
38+
<plugin>
39+
<groupId>org.apache.maven.plugins</groupId>
40+
<artifactId>maven-war-plugin</artifactId>
41+
<version>2.6</version>
42+
<configuration>
43+
<failOnMissingWebXml>false</failOnMissingWebXml>
44+
</configuration>
45+
</plugin>
46+
47+
</plugins>
48+
</build>
49+
</project>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.bobocode.config;
2+
3+
import org.springframework.context.annotation.ComponentScan;
4+
import org.springframework.context.annotation.ComponentScan.Filter;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.stereotype.Controller;
7+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
8+
9+
/**
10+
* This class provides application root (non-web) configuration for a basic spring application context
11+
* (containing middle-tire services, datasource, etc.).
12+
* The configuration must exclude the web layer of the application.
13+
* <p>
14+
* todo: mark this class as config
15+
* todo: enable component scanning for all packages in "com.bobocode"
16+
* todo: ignore all web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) using exclude filter
17+
*/
18+
public class RootConfig {
19+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.bobocode.config;
2+
3+
import com.bobocode.util.ExerciseNotCompletedException;
4+
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
5+
6+
/**
7+
* This class is used to configure DispatcherServlet and links it with application config classes
8+
*/
9+
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
10+
@Override
11+
protected Class<?>[] getRootConfigClasses() {
12+
throw new ExerciseNotCompletedException(); //todo: use {@link RootConfig} as root application config class
13+
}
14+
15+
@Override
16+
protected Class<?>[] getServletConfigClasses() {
17+
throw new ExerciseNotCompletedException(); //todo: use {@link WebConfig} as ServletConfig class
18+
}
19+
20+
@Override
21+
protected String[] getServletMappings() {
22+
throw new ExerciseNotCompletedException(); //todo: provide default servlet mapping ("/")
23+
}
24+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.bobocode.config;
2+
3+
import org.springframework.context.annotation.ComponentScan;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
6+
7+
/**
8+
* This class provides web (servlet) related configuration. In the Web MVC framework,
9+
* each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined
10+
* in the root ApplicationContext.
11+
* <p>
12+
* todo: mark this class as Spring config class
13+
* todo: enable web mvc using annotation
14+
* todo: enable component scanning for package "web"
15+
*/
16+
17+
public class WebConfig {
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.bobocode.web.controller;
2+
3+
/**
4+
* Welcome controller that consists of one method that handles get request to "/welcome" and respond with a message.
5+
* <p>
6+
* todo: mark this class as Spring controller
7+
* todo: configure HTTP GET mapping "/welcome" for method {@link WelcomeController#welcome()}
8+
* todo: tell Spring that {@link WelcomeController#welcome()} method provides response body without view
9+
*/
10+
11+
public class WelcomeController {
12+
13+
public String welcome() {
14+
return "Welcome to Spring MVC!";
15+
}
16+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package com.bobocode;
2+
3+
import com.bobocode.config.RootConfig;
4+
import com.bobocode.config.WebConfig;
5+
import com.bobocode.web.controller.WelcomeController;
6+
import org.junit.jupiter.api.*;
7+
import org.springframework.context.annotation.ComponentScan;
8+
import org.springframework.context.annotation.ComponentScan.Filter;
9+
import org.springframework.context.annotation.Configuration;
10+
import org.springframework.context.annotation.FilterType;
11+
import org.springframework.stereotype.Controller;
12+
import org.springframework.web.bind.annotation.GetMapping;
13+
import org.springframework.web.bind.annotation.ResponseBody;
14+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
15+
16+
import java.util.List;
17+
import java.util.stream.Collectors;
18+
import java.util.stream.Stream;
19+
20+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
21+
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
23+
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
24+
class WebAppConfigurationTest {
25+
26+
@Test
27+
@Order(1)
28+
@DisplayName("RootConfig class is marked as @Configuration")
29+
void rootConfigClassIsMarkedAsConfiguration() {
30+
Configuration configuration = RootConfig.class.getAnnotation(Configuration.class);
31+
32+
assertNotNull(configuration);
33+
}
34+
35+
@Test
36+
@Order(2)
37+
@DisplayName("RootConfig class enables @ComponentScan")
38+
void rootConfigClassEnablesComponentScan() {
39+
ComponentScan componentScan = RootConfig.class.getAnnotation(ComponentScan.class);
40+
41+
assertNotNull(componentScan);
42+
}
43+
44+
@Test
45+
@Order(3)
46+
@DisplayName("RootConfig @ComponentScan contains base packages")
47+
void rootConfigComponentScanPackages() {
48+
ComponentScan componentScan = RootConfig.class.getAnnotation(ComponentScan.class);
49+
String[] packages = componentScan.basePackages();
50+
if (packages.length == 0) {
51+
packages = componentScan.value();
52+
}
53+
54+
assertThat(packages).contains("com.bobocode");
55+
}
56+
57+
@Test
58+
@Order(4)
59+
@DisplayName("RootConfig @ComponentScan contains web scan filters")
60+
void rootConfigComponentScanFilters() {
61+
ComponentScan componentScan = RootConfig.class.getAnnotation(ComponentScan.class);
62+
Filter[] filters = componentScan.excludeFilters();
63+
List<Class> filteredClasses = getFilteredClasses(filters);
64+
65+
assertThat(filters.length).isEqualTo(2);
66+
assertThat(filters[0].type()).isEqualTo(FilterType.ANNOTATION);
67+
assertThat(filters[1].type()).isEqualTo(FilterType.ANNOTATION);
68+
assertThat(filteredClasses.toArray()).containsExactlyInAnyOrder(EnableWebMvc.class, Controller.class);
69+
}
70+
71+
@Test
72+
@Order(5)
73+
@DisplayName("WebConfig is marked as @Configuration")
74+
void webConfigIsMarkedAsConfiguration() {
75+
Configuration configuration = WebConfig.class.getAnnotation(Configuration.class);
76+
77+
assertNotNull(configuration);
78+
}
79+
80+
@Test
81+
@Order(6)
82+
@DisplayName("WebConfig enables @ComponentScan")
83+
void webConfigEnablesComponentScan() {
84+
ComponentScan componentScan = WebConfig.class.getAnnotation(ComponentScan.class);
85+
86+
assertNotNull(componentScan);
87+
}
88+
89+
@Test
90+
@Order(7)
91+
@DisplayName("WebConfig @ComponentScan contains web packages")
92+
void webConfigComponentScanPackages() {
93+
ComponentScan componentScan = WebConfig.class.getAnnotation(ComponentScan.class);
94+
95+
assertThat(componentScan.basePackages()).contains("com.bobocode.web");
96+
}
97+
98+
@Test
99+
@Order(8)
100+
@DisplayName("WebConfig is marked with @EnableWebMvc")
101+
void webConfigEnablesWebMvc() {
102+
EnableWebMvc enableWebMvc = WebConfig.class.getAnnotation(EnableWebMvc.class);
103+
104+
assertNotNull(enableWebMvc);
105+
}
106+
107+
@Test
108+
@Order(9)
109+
@DisplayName("Initializer method is overridden with RootConfig class")
110+
void initializerRootConfigClasses() {
111+
WebAppInitializerWrapper webAppInitializerWrapper = new WebAppInitializerWrapper();
112+
113+
assertThat(webAppInitializerWrapper.getRootConfigClasses()).contains(RootConfig.class);
114+
}
115+
116+
@Test
117+
@Order(10)
118+
@DisplayName("Initializer method is overridden with WebConfig class")
119+
void initializerWebConfigClasses() {
120+
WebAppInitializerWrapper webAppInitializerWrapper = new WebAppInitializerWrapper();
121+
122+
assertThat(webAppInitializerWrapper.getServletConfigClasses()).contains(WebConfig.class);
123+
}
124+
125+
@Test
126+
@Order(11)
127+
@DisplayName("Dispatcher Servlet mapping is \"/\"")
128+
void dispatcherServletMapping() {
129+
WebAppInitializerWrapper webAppInitializerWrapper = new WebAppInitializerWrapper();
130+
131+
assertThat(webAppInitializerWrapper.getServletMappings()).contains("/");
132+
}
133+
134+
@Test
135+
@Order(12)
136+
@DisplayName("WelcomeController is marked as @Controller")
137+
void welcomeControllerIsMarkedAsController() {
138+
Controller controller = WelcomeController.class.getAnnotation(Controller.class);
139+
140+
assertNotNull(controller);
141+
}
142+
143+
@Test
144+
@Order(13)
145+
@DisplayName("WelcomeController method is marked as Get method")
146+
void welcomeControllerMethodIsMarkedAsGetMethod() throws NoSuchMethodException {
147+
GetMapping getMapping = WelcomeController.class.getDeclaredMethod("welcome").getAnnotation(GetMapping.class);
148+
149+
assertNotNull(getMapping);
150+
}
151+
152+
@Test
153+
@Order(14)
154+
@DisplayName("WelcomeController Get method is marked properly")
155+
void welcomeControllerMethodMapping() throws NoSuchMethodException {
156+
GetMapping getMapping = WelcomeController.class
157+
.getDeclaredMethod("welcome").getAnnotation(GetMapping.class);
158+
159+
assertThat(getMapping.value()).contains("/welcome");
160+
}
161+
162+
@Test
163+
@Order(15)
164+
@DisplayName("WelcomeController Get method is marked as @ResponseBody")
165+
void welcomeControllerMethodIsMarkedAsResponseBody() throws NoSuchMethodException {
166+
ResponseBody responseBody = WelcomeController.class
167+
.getDeclaredMethod("welcome").getAnnotation(ResponseBody.class);
168+
169+
assertNotNull(responseBody);
170+
}
171+
172+
private List<Class> getFilteredClasses(Filter[] filters) {
173+
return Stream.of(filters).flatMap(filter -> Stream.of(filter.value())).collect(Collectors.toList());
174+
}
175+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.bobocode;
2+
3+
import com.bobocode.config.WebAppInitializer;
4+
5+
class WebAppInitializerWrapper extends WebAppInitializer {
6+
public String[] getServletMappings() {
7+
return super.getServletMappings();
8+
}
9+
10+
public Class[] getRootConfigClasses() {
11+
return super.getRootConfigClasses();
12+
}
13+
14+
public Class<?>[] getServletConfigClasses() {
15+
return super.getServletConfigClasses();
16+
}
17+
}

3-0-spring-framework/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
<modules>
1616
<module>3-0-1-hello-spring-mvc</module>
17+
<module>3-1-1-dispatcher-servlet-initializer</module>
1718
</modules>
1819

1920
</project>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>java-web-course-util</artifactId>
7+
<groupId>com.bobocode</groupId>
8+
<version>1.0-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>java-web-util</artifactId>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>io.codearte.jfairy</groupId>
17+
<artifactId>jfairy</artifactId>
18+
<version>0.5.9</version>
19+
</dependency>
20+
</dependencies>
21+
22+
</project>

0 commit comments

Comments
 (0)