Skip to content

Commit

Permalink
Merge branch 'release/v1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
mwarman committed May 16, 2015
2 parents 1ba9992 + bfd95db commit 1bf07ca
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 24 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,14 @@ The project provides examples of Spring Security integration. The web service e
The project demonstrates how to use Spring Profiles to activate (or deactivate) application components and configuration. The profiles illustrated are: batch, hsqldb, and mysql.

#### Unit Tests
The project contains unit test examples for standard components such as business services or batch beans and examples for the web service endpoints using Mock objects.
The project contains unit test examples for standard components such as business services or batch beans and examples for the web service endpoints using Mock objects. Perform complete end-to-end testing with Spring MVC mocking or leverage Mockito to stub or spy business components.

#### Actuator Monitoring and Management
The project illustrates the use of Spring Boot Actuator for application monitoring and management. The application demonstrates the recording of custom metrics. Also, custom Maven project attributes are incorporated into the Actuator info endpoint.

#### API Documentation Generator
The project includes [Springfox](http://springfox.github.io/springfox/) Swagger integration to automatically generate API docs for the RESTful web service endpoints. This feature may be activated using the *"docs"* Spring profile.

## Languages

This project is authored in Java.
Expand Down
25 changes: 23 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,30 @@

<groupId>com.leanstacks</groupId>
<artifactId>skeleton-ws-spring-boot</artifactId>
<version>1.0.1</version>
<version>1.2.0</version>
<name>Web Services Project Skeleton</name>
<description>Skeleton project for RESTful web services using Spring Boot.</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
<version>1.2.3.RELEASE</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version>
<guava.version>18.0</guava.version>
<swagger.version>2.0.0-SNAPSHOT</swagger.version>
</properties>

<repositories>
<repository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
</repository>
</repositories>

<dependencies>
<dependency>
Expand Down Expand Up @@ -61,6 +70,18 @@
<version>${guava.version}</version>
</dependency>

<!-- Dependencies for Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>

<!-- Dependencies for Unit Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/com/leanstacks/ws/ApiDocsConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.leanstacks.ws;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import com.google.common.base.Predicate;

/**
* The ApiDocsConfiguration class provides configuration beans for the Swagger
* API documentation generator.
*
* @author Matt Warman
*/
@Profile("docs")
@Configuration
@EnableSwagger2
public class ApiDocsConfiguration {

/**
* Create a Docket class to be used by Springfox's Swagger API Documentation
* framework. See http://springfox.github.io/springfox/ for more
* information.
* @return A Docket instance.
*/
@Bean
public Docket docket() {
Predicate<String> paths = PathSelectors.ant("/api/**");

ApiInfo apiInfo = new ApiInfoBuilder()
.title("Project Skeleton for Spring Boot Web Services")
.description(
"The Spring Boot web services starter project provides a foundation to rapidly construct a RESTful web services application.")
.contact("LeanStacks.com").version("1.2.0").build();

Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo).select().paths(paths).build();

return docket;
}

}
99 changes: 84 additions & 15 deletions src/main/java/com/leanstacks/ws/SecurityConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
Expand All @@ -22,7 +24,7 @@
*/
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public class SecurityConfiguration {

@Autowired
private AccountAuthenticationProvider accountAuthenticationProvider;
Expand Down Expand Up @@ -55,21 +57,88 @@ public void configureGlobal(AuthenticationManagerBuilder auth)
auth.authenticationProvider(accountAuthenticationProvider);

}

/**
* This inner class configures the WebSecurityConfigurerAdapter instance for
* the web service API context paths.
*
* @author Matt Warman
*/
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("USER")
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

}

/**
* This inner class configures the WebSecurityConfigurerAdapter instance for
* the Spring Actuator web service context paths.
*
* @author Matt Warman
*/
@Configuration
@Order(2)
public static class ActuatorWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.csrf().disable()
.antMatcher("/actuators/**")
.authorizeRequests()
.anyRequest().hasRole("SYSADMIN")
.and()
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);

}

}

/**
* This inner class configures the WebSecurityConfigurerAdapter instance for
* any remaining context paths not handled by other adapters.
*
* @author Matt Warman
*/
@Profile("docs")
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").hasRole("USER")
.antMatchers("/actuators/**").hasRole("SYSADMIN")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();

}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public class GreetingController extends BaseController {
value = "/api/greetings",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Greeting>> getGreetings() throws Exception {
public ResponseEntity<Collection<Greeting>> getGreetings() {
logger.info("> getGreetings");

Collection<Greeting> greetings = greetingService.findAll();
Expand Down Expand Up @@ -80,8 +80,7 @@ public ResponseEntity<Collection<Greeting>> getGreetings() throws Exception {
value = "/api/greetings/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Greeting> getGreeting(@PathVariable Long id)
throws Exception {
public ResponseEntity<Greeting> getGreeting(@PathVariable Long id) {
logger.info("> getGreeting");

Greeting greeting = greetingService.findOne(id);
Expand Down Expand Up @@ -117,7 +116,7 @@ public ResponseEntity<Greeting> getGreeting(@PathVariable Long id)
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Greeting> createGreeting(
@RequestBody Greeting greeting) throws Exception {
@RequestBody Greeting greeting) {
logger.info("> createGreeting");

Greeting savedGreeting = greetingService.create(greeting);
Expand Down Expand Up @@ -152,7 +151,7 @@ public ResponseEntity<Greeting> createGreeting(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Greeting> updateGreeting(
@RequestBody Greeting greeting) throws Exception {
@RequestBody Greeting greeting) {
logger.info("> updateGreeting");

Greeting updatedGreeting = greetingService.update(greeting);
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/com/leanstacks/ws/web/docs/ApiDocsController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.leanstacks.ws.web.docs;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
* The ApiDocsController is a Spring MVC web controller class which serves the
* Swagger user interface HTML page.
*
* @author Matt Warman
*/
@Profile("docs")
@Controller
public class ApiDocsController {

/**
* Request handler to serve the Swagger user interface HTML page configured
* to the mapped context path.
*
* @return A String name of the Swagger user interface HTML page name.
*/
@RequestMapping("/docs")
public String getSwaggerApiDocsPage() {
return "swagger-ui.html";
}

}
1 change: 1 addition & 0 deletions src/main/resources/config/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

##
# Profile Configuration
# profiles: hsqldb, mysql, batch, docs
##
spring.profiles.active=hsqldb,batch

Expand Down
11 changes: 11 additions & 0 deletions src/test/java/com/leanstacks/ws/AbstractControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.leanstacks.ws.web.api.BaseController;

/**
* This class extends the functionality of AbstractTest. AbstractControllerTest
Expand All @@ -38,6 +39,16 @@ protected void setUp() {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}

/**
* Prepares the test class for execution of web tests. Builds a MockMvc
* instance using standalone configuration facilitating the injection of
* Mockito resources into the controller class.
* @param controller A controller object to be tested.
*/
protected void setUp(BaseController controller) {
mvc = MockMvcBuilders.standaloneSetup(controller).build();
}

/**
* Maps an Object into a JSON String. Uses a Jackson ObjectMapper.
* @param obj The Object to map.
Expand Down
Loading

0 comments on commit 1bf07ca

Please sign in to comment.