Skip to content

Latest commit

 

History

History
320 lines (270 loc) · 14 KB

SpringBoot_By_Siva_Lab.md

File metadata and controls

320 lines (270 loc) · 14 KB

Spring Boot - The Missing Guide and Spring boot Tips

Spring Boot The Missing Guide

image image image image image image image image

Template Framework used by Spring

image image

Spring handles transactions & security using AOP & proxy design

image image image

Bean Configuration

AutoConfiguration Works

image image image image image

Autoconfiguration

Validation Configuration Properties using JavaBeans validation API

  • We can use Java Bean API @NonEmpty etc on fields od property config class image image

Binding Properties to Immutable Objects using Contructor Binding

  • Property coniguration should be read only meaning no one can update those properties values later , for that we have to make that prperty class as Immutable
  • Remove all setters , fields shoud be final and create constructor
  • @ConstructorBinding use this annotation for configuration using constructor
  • image

Binding Properties to Java Records for Java14+


Spring Boot Tips

Dependecy Managment

  • Dependecymanagment tag : we can exclude any transative dependency and we can define in parent project as POM

Managing application configuration

  • Default Values ex. applicartion.properties
  • Profile specific overrides ex. application-{profie}.properties
  • environment variables ex. SERVER_PORT=9090
  • we can validate property file fields using @Validate
  • We can bind propertiy files with Record from jdk16+

Logging Tips

Mapped Daignostic COntext

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> 
  <layout>
    <Pattern>%d{DATE} %p %X{sessionId} %X{userId} %c - %m%n</Pattern>
  </layout> 
</appender>
#logging.level.root=INFO
#logging.level.com.sivalabs=TRACE
#logging.pattern.console=%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(UserId:%X{UserId:-Guest}){magenta} %clr(Context:%X){magenta}  %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n
#logging.file.name=myapp.log
<configuration>
    <springProperty scope="context" name="region" source="app.region" defaultValue="us-east-1"/>
    <property name="LOG_FILE" value="${region}-myapp.log"/>
    <property name="CONSOLE_LOG_PATTERN" value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(UserId:%X{UserId:-Guest}){magenta} %clr(Context:%X){magenta}  %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n ${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } [UserId:%X{UserId:-Guest}] [Context:%X] --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <include resource="org/springframework/boot/logging/logback/defaults.xml" />
    <include resource="org/springframework/boot/logging/logback/console-appender.xml" />
    <include resource="org/springframework/boot/logging/logback/file-appender.xml" />

    <springProfile name="local">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>

    <springProfile name="!local">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

    <logger name="com.sivalabs" level="DEBUG"/>
    <logger name="org.springframework" level="INFO"/>
</configuration>

image

Testing

image

  • @WebMvcTest
@WebMvcTest(controllers = ProductController.class)
class ProductControllerTest {

    @MockBean
    private ProductService productService;

    @Autowired
    private MockMvc mockMvc;

    @Test
    void shouldReturnActiveProducts() throws Exception {
        BDDMockito.given(productService.getAllProducts()).willReturn(List.of());

        mockMvc.perform(get("/api/products"))
                .andExpect(status().isOk());
    }
}

IT using TestContainers

Exception Handling in spring boot

Exception Handling using problem-spring-web

@RestControllerAdvice
class ExceptionHandling implements ProblemHandling {

    @ExceptionHandler
    public ResponseEntity<Problem> handle(CustomerNotFoundException e, NativeWebRequest request) {
        ThrowableProblem problem = Problem.builder().withStatus(Status.NOT_FOUND)
                .withTitle("Customer Not Found")
                .withDetail(e.getMessage())
                .build();
        return create(problem, request);
    }
}

Acuator

spring.boot.admin.client.url=http://localhost:9090

management.endpoints.web.exposure.include=*
management.endpoint.health.show-components=always
management.endpoint.health.show-details=always

management.info.env.enabled=true
management.info.java.enabled=true
management.info.os.enabled=true

info.myapp.name=ActuatorDemo
info.myapp.version=1.0.1
info.myapp.author=SivaLabs
info.myapp.website=https://sivalabs.in

[email protected]@
[email protected]@
[email protected]@

Monitoring Spring Boot Application by Spring Boot Admin

<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>3.0.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
@SpringBootApplication
@EnableAdminServer
public class SpringBootAdminServerApplication {

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

}
  • Add spring-boot-admin-starter-client to your dependencies:
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>3.0.4</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
spring.boot.admin.client.url=http://localhost:8080  (1)
management.endpoints.web.exposure.include=*  (2)
management.info.env.enabled=true (3)

image image

Generating Swagger docs for SpringBoot REST APIs

 <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
            <version>1.6.9</version>
        </dependency>
  • For secutiry authorization at global
@Configuration
@OpenAPIDefinition(info = @Info(title = "SpringBoot Tips API", version = "v1"))
@SecurityScheme(
       name = "jwtBearerAuth",
       type = SecuritySchemeType.HTTP,
       bearerFormat = "JWT",
       scheme = "bearer"
)
public class SwaggerConfig {
}
@RestController
@RequestMapping("/api/bookmarks")
@RequiredArgsConstructor
@SecurityRequirement(name = "jwtBearerAuth")
@Tag(name = "Bookmarks")
public class BookmarkController {
    private final BookmarkService bookmarkService;

    @GetMapping
    public List<Bookmark> getAllBookmarks() {
        return bookmarkService.getAllBookmarks();
    }

    @GetMapping("/{id}")
    public ResponseEntity<Bookmark> getBookmarkById(@PathVariable Long id) {
        Bookmark bookmark = bookmarkService.getBookmarkById(id);
        return ResponseEntity.ok(bookmark);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    //@Operation(description = "Create a new bookmark", security = @SecurityRequirement(name = "jwtBearerAuth"))
    @ApiResponses(
            value = {
                    @ApiResponse(description = "Successfully created new bookmark", responseCode = "201"),
                    @ApiResponse(description = "Forbidden", responseCode = "403"),
            }
    )
    public Bookmark createBookmark(@RequestBody @Valid Bookmark bookmark) {
        return bookmarkService.createBookmark(bookmark);
    }

}