Resources

Presentation

Avantages :

  • enables us to focus on the business logic of the application instead of configurations and dependency management
  • a very gradual learning curve
  • minimum viable product (MVP) that is production-ready within maybe a couple of days or hours.

mvn spring-boot:run –debug

Components

Spring Boot

  • Standalone: self-contained and easily deployable. It can start with its own embedded Tomcat, Jetty, Undertow web container, or as a console application from a just standard file such as Java Archive (JAR) or Web Archive (WAR).
  • Production ready : such as monitoring, connection pools, externalized configuration
  • Maven : spring-boot-starter-parent

Spring Boot Actuator

Spring Boot Actuator is a production-ready feature for monitoring and managing a Spring Boot application using HTTP endpoints or JMX

Spring Boot Actuator’s health endpoint is really helpful for checking the status of Spring Boot application and dependent systems such as databases, message queues, and so on.
By default, only the /info and /health endpoints are exposed
Custom metrics using Micrometer

Spring Security

Spring Boot

Main Application

1
2
3
4
5
6
7
8

@SpringBootApplication
public class CmsApplication {

public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}

Command Line Runner

Command-line runners are a useful functionality to execute the various types of code that only have to be run once, after startup
We can also use an @Order annotation or implement an Ordered interface so as to define the exact order in which we want Spring Boot to execute them.

1
2
3
4
   @Bean
public StartupRunner schedulerRunner() {
return new StartupRunner();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.cyrgue.bookpub;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.CommandLineRunner;

public class StartupRunner implements CommandLineRunner {

protected final Log log = LogFactory.getLog(getClass());

@Override
public void run(String... args) throws Exception {
log.info("Spring start uop");
}
}

Rest Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

@RestController
@RequestMapping("/api/user")
@Api(tags = "user", description = "User API")
public class UserResource {

private final UserService userService;

public UserResource(UserService userService) {
this.userService = userService;
}

@ApiOperation(
value = "Retrieve all users ",
notes = "A list of user is returned. Current pagination is not supported.",
response = User.class,
responseContainer = "List",
produces = "application/json")
@GetMapping
public ResponseEntity<List<User>> findAll() {
return ResponseEntity.ok(this.userService.findAll());
}

@GetMapping(value = "/{id}")
public Resource<User> findOne(@PathVariable("id") String id) {
return null;
}

@PostMapping
public ResponseEntity<User> create(@RequestBody @Valid UserRequest request) throws Exception {
return new ResponseEntity<>(this.userService.create(request), HttpStatus.CREATED);
}
}

Configuration

Cors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

@Configuration
public class WebConfig {

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**").allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD");
}
};
}
}

Swagger

1
2
3
4
5
6
7
8
9
10
11
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any()).build();
}
}

Spring Data

Spring JPA

Configuration

1
2
3
4
5
6
7
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:~/retroboard
spring.datasource.username=sa
spring.datasource.password=

Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
@Table(name = "rb_comment")
@EntityListeners(AuditingEntityListener.class)
@Data
public class Comment {

@Id
@GeneratedValue
private Long id;

private String comment;

@Enumerated(EnumType.STRING)
private CommentType type;

@CreatedDate
private Timestamp createdDate;

@CreatedBy
private String createdBy;
}

Repository

1
2
3
4
5
6
7
8
9
public interface CommentRepository extends JpaRepository<Comment, Long> {

@Query("SELECT c FROM Comment c WHERE year(c.createdDate) = ?1 AND
month(c.createdDate) = ?2 AND
day(c.createdDate) = ?3")
List<Comment> findByCreatedYearAndMonthAndDay(int year, int month,
int day);

}

Mongo

Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

@Configuration
@EnableMongoRepositories({"com.cyrgue.bfd"})
public class PersistenceConfig {

public @Bean MongoClient mongoClient(
@Value("#{systemEnvironment['mongodb.host'] ?: 'localhost'}") String host,
@Value("#{systemEnvironment['mongodb.port'] ?: 27017}") Integer port) {

return new MongoClient(new ServerAddress(host, port));
}

public @Bean MongoTemplate mongoTemplate(
MongoClient mongo,
@Value("#{systemEnvironment['mongodb.database'] ?: 'dashboard'}") String database) throws Exception {

MongoTemplate template = new MongoTemplate(new SimpleMongoDbFactory(mongo, database));
template.setWriteResultChecking(WriteResultChecking.EXCEPTION);
template.setWriteConcern(WriteConcern.ACKNOWLEDGED);
return template;
}
}

Entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;

@Getter
@Document(collection = "user")
public class User {

@Id
String id;

String email;

String firstName;

String lastName;

Role role;

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}

User(String firstName, String lastName, String email, Role role) {
this.id = UUID.randomUUID().toString();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.role = role;
}

public static class UserBuilder {

private String firstName;
private String lastName;
private String email;
private Role role;

UserBuilder(String email) {
this.email = email;
}

public static UserBuilder buildFrom(String email) {
return new UserBuilder(email);
}

public UserBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}

public UserBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}

public UserBuilder withRoleName(String roleName) {
this.role = roleName == null ? Role.READER : Arrays.asList(Role.values())
.stream()
.filter(r -> r.equals(Role.valueOf(roleName)))
.findFirst().orElse(Role.READER);

return this;
}

public User build() {
return new User(firstName, lastName, email, role);
}
}
}

Repository

1
2
3
public interface UserRepository extends MongoRepository<User, String> {
List<User> findByEmail(String email);
}

Logging

Apache Commons Logging API => provided by Spring Framework’s spring-jcl module
The simplest way to do that is through the starters, which all depend on spring-boot-starter-logging. For a web application, you need only spring-boot-starter-web

Ref