Create a RESTful application
In these days, more and more poeples are using Spring Boot to get autoconfiguration support and quicker build lifecycle.
For those new to Spring, the regular approache(none Sprinb Boot) is more easy to understand Spring essential configurations.
Let's us create a Maven based Java EE 7 web application to introduce how to configure a Spring MVC web application in details, then switch to Spring Boot, thus you can compare these two approaches, and understand how Spring Boot simplifies configurations.
Create a regular web project
Create a Maven web project.
Use the official Java EE 7 web archetype to generate the project skeleton, replace the value of archetypeId and package to yours.
mvn -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=webapp-javaee7 -DarchetypeVersion=1.1 -DgroupId=your_group_id -DartifactId=angularjs-springmvc-sample -Dversion=1.0.0-SNAPSHOT -Dpackage=com.hantsylabs.restsampels -Darchetype.interactive=false --batch-mode archetype:generate
Add Spring IO platform
platform-bom
to the dependencyManagement.<dependencyManagement> <dependencies> <!-- Spring BOM --> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>2.0.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
You can also use platform-bom as parent of this project.
Read the Apache Maven docs to understand Dependency Mechanism.
Add essential dependencies for Spring MVC.
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> </dependency> <!-- Spring security --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> <!-- Spring Data --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> </dependency> <!--bean validation --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
Besides Spring core dependencies, Spring MVC, Spring Security , Hibernate, JPA/Spring Data JPA, Bean validation are also required.
If you would like use
@Inject
instead of@Autowire
in codes, add inject dependency.<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
Enable Spring MVC
DisptachServlet
.Declare a
AbstractAnnotationConfigDispatcherServletInitializer
bean.@Order(0) public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class, // DataSourceConfig.class, // JpaConfig.class, // DataJpaConfig.class,// SecurityConfig.class,// Jackson2ObjectMapperConfig.class,// MessageSourceConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return new Class[] { WebConfig.class, // SwaggerConfig.class // }; } @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceEncoding(true); return new Filter[] { encodingFilter }; } }
Serlvet 3.0 provides a new feature ServletInitializer to configure web applciation without web.xml.
Spring has its WebApplicationInitializer interface, there are a few classes implement this interface,
AbstractAnnotationConfigDispatcherServletInitializer
includes configuration of Spring Dispatch Servlet, and leave some room to customizeDispatchServlet
.getRootConfigClasses
specifies the configuration classes should be loaded for the Spring infrastrucuture.getServletConfigClasses
specifies the configurations depend on Servlet specification, esp, web mvc related configurations.getServletMappings
is the SpringDispatchServlet
mapping URL pattern.getServletFilters
are the filters will be applied on the SpringDispatchServlet
.Spring MVC
DispatchServlet
is configured in the super classes, explore the details if you are interested in it.Enable Spring Security
@Order(1) public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { }
Similiar with
AbstractAnnotationConfigDispatcherServletInitializer
, it is aWebApplicationInitializer
implementation, and aleady configured Spring Security filter chain for you.Configuration classes.
Therea are a few configuration classes already created for this sample application, as you saw in above
AppInitializer
.Every configuration should be annotated with
@Configuration
.It is recommended to slipt the configurations into different classes by categories. eg. In this sample the configuration classes includes:
AppConfig
is the base configuration.DataSourceConfig
is the configuration forDataSource
.JpaConfig
is the configuration for JPA and transacation.DataJpaConfig
is the configuration for Spring Data JPA extension support.SecurityConfig
is the Spring Security configuration.Jackson2ObjectMapperConfig
is the customized JacksonObjectMapper
bean.MessageSourceConfig
is the configuration forMessageSource
.WebConfig
is the configuration for Spring MVC.SwaggerConfig
is the configuration for Swagger schema APIs.
`@ComponentScan` defines the component scanning strategy for loading Spring `Component` at the application starts up.
The **excludeFilters** property define rules to exclude some components. `AppConfig` only scans none web beans, and `WebConfig` only scan web relates beans.
**@PropertySource** configures the properties file will be loadded by Spring, later you can read the properties by `Environment`. Check the usage in `DataSourceConfig` class.
Have a look at the content of `WebConfig` which is responsible for configuring Spring MVC in details, including resource handling, view, view resolvers etc.
public class WebConfig extends SpringDataWebConfiguration {
}
Generally, `WebMvcConfigurerAdapter` is use for customizing MVC details. `SpringDataWebConfiguration` is a subclass of `WebMvcConfigurerAdapter`, it is from Spring data project, and add pagination, sort, and domain object conversion support. Open the source code of `SpringDataWebConfiguration` and research yourself.
`SecurityConfig` is the Spring security configuration details.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/**/*.html", //
"/css/**", //
"/js/**", //
"/i18n/**",//
"/libs/**",//
"/img/**", //
"/webjars/**",//
"/ico/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/**")
.authenticated()
.and()
.authorizeRequests()
.anyRequest()
.permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.and()
.csrf()
.disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser("admin").password("test123").authorities("ROLE_ADMIN")
.and()
.withUser("test").password("test123").authorities("ROLE_USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
`AuthenticationManagerBuilder` is the simplest entry to configure the essential security requirements. *InMemory* authentication is frequently used for demonstration. In a real world project, it is better to implement a `UserDetailsService` to load users from database.
Get the [codes](https://github.com/hantsy/angularjs-springmvc-sample) from my github account to explore all configuration classes.