Skip to content

⚡️ Preconfigured components to speedup Spring Boot development

Notifications You must be signed in to change notification settings

jpomykala/spring-higher-order-components

Repository files navigation

spring-hoc

Build Status Maven Central codecov Maintainability

Boilerplate components for Spring Boot.

Installation

<dependency>
  <groupId>com.jpomykala</groupId>
  <artifactId>spring-higher-order-components</artifactId>
  <version>1.0.11</version>
</dependency>

Check version in maven repository

Motivation

  • Write inline code
  • Duplicate code a few times in different spots
  • Extract duplicate code into methods
  • Use your abstractions for a while
  • See how that code interacts with other code
  • Extract common functionality into internal library
  • Use internal library for extended periods of time
  • Really understand how all of the pieces come together
  • Create external open source library (we are here now)

source: https://nickjanetakis.com


@EnableEmailSending annotation

This component gives you simple API to send emails using Amazon SES service. Spring HOC will automatically create for you Amazon SES component if bean doesn't exist.

Configuration

  • Provide verified sender email address spring-hoc.mail.sender-email-address
  • Provide AWS credentials spring-hoc.aws.access-key, spring-hoc.aws.secret-key, spring-hoc.aws.region

Example application.yml configuration for e-mail sending

spring-hoc:
  aws:
    access-key: xxxxxxxx
    secret-key: xxxxxxxx
    region: eu-west-1
  mail:
    sender-email-address: "[email protected]"    

This properties are required.

Tip

You can put My Company Name <[email protected]> in sender-email-address property to show "My Company Name" in e-mail apps instead plain e-mail. Reference: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-email-concepts-email-format.html

How to send e-mail?

Use EmailRequest step builder to create request.

EmailRequest.builder()
            .to("[email protected]")
            .subject("Hey, I just met you and this is crazy")
            .body("But here's my number, so call me maybe")
            .build();

Now it's time to send email. You have 2 options here.

  • @Autowire MailService and invoke sendEmail(EmailRequest).
  • Publish EmailRequest using ApplicationEventPublisher

That's all!

Example application with sending email (SES)

@SpringBootApplication
@EnableEmailSending
public class MySpringBootApplication {

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

  // Send e-mail by event publishing, Spring HOC will listen to EmailRequest objects 
  @Autowired
  private ApplicationEventPublisher eventPublisher;

  @GetMapping("/send-email-by-event-publishing")
  public void sendEmailByEventPublishing(){
    EmailRequest emailRequest = EmailRequest.builder()
            .to("[email protected]")
            .subject("Hey, I just met you and this is crazy [event publishing]")
            .body("But here's my number, so call me maybe")
            .build();

    eventPublisher.publishEvent(emailRequest);
  }
  
  // Send e-mail by mail service provided by Spring HOC and @EnableEmailSending annotation
  @Autowired
  private MailService mailService;

  @GetMapping("/send-email-by-mail-service")
  public void sendEmailByMailService(){
    EmailRequest emailRequest = EmailRequest.builder()
            .to("[email protected]")
            .subject("Hey, I just met you and this is crazy [mail service]")
            .body("But here's my number, so call me maybe")
            .build();

    mailService.send(emailRequest);
  }
}

@EnableRequestLogging annotation

Adds logging requests, populate MDC with:

  • user (IP address by default)
  • requestId (UUID by default).

Example application with request logging

@SpringBootApplication
@EnableRequestLogging
public class MySpringBootApplication {

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

  @Autowired
  private MyUserService userService;

  // [OPTIONAL] customize configuration
  @Bean
  public LoggingFilter loggingFilter(LoggingFilterFactory loggingFilterFactory) {
    return loggingFilterFactory
            .withPrincipalProvider(new PrincipalProvider() {
              @Override
              public String getPrincipal(HttpServletRequest request) {
                return userService.findUserName(request);
              }
            })
            .createFilter();
  }
}

Customization of request logging

@Bean
public LoggingFilter loggingFilter(LoggingFilterFactory loggingFilterFactory){
  return loggingFilterFactory
          .withPrincipalProvider() // [optional] PrincipalProvider implementation 
          .withRequestIdProvider() // [optional] RequestIdProvider implementation
          .withCustomMdc("user", "[u:%s][rid:%s]") // [optional] MDC key, String.format()
          .createFilter();
}

@EnableFileUploading annotation

This annotation autoconfigures Amazon S3 component if bean doesn't exit.

@Autowire UploadService gives you ability to upload files using overloaded methods:

  • void upload(@NotNull UploadRequest uploadRequest)
  • void upload(@NotNull MultipartFile file)
  • void upload(@NotNull MultipartFile file, @NotNull String path)
  • void upload(byte[] bytes, String fileKey)
  • void upload(byte[] bytes, String fileKey, ObjectMetadata metadata)
  • String upload(byte[] bytes) // path is autogenerated (sha256 hash)

Example application.yml configuration for file uploading

spring-hoc:
  aws:
    access-key: xxxxxxxx
    secret-key: xxxxxxxx
    region: eu-west-1
  s3:
    bucket-name: my-bucket

This properties are required.*

Example application with files uploading

@SpringBootApplication
@EnableFileUploading
public class MySpringBootApplication {

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

  @Autowired
  private UploadService uploadService;

  @GetMapping("/upload-file")
  public String uploadFile(@RequestBody MultipartFile multipartFile) throws IOException {
    String s3DownloadUrl = uploadService.upload(multipartFile);
    return s3DownloadUrl;
  }
}

@EnableResponseWrapping annotation

Every @RestController output will be wrapped into RestResponse<T> object for JSON it will look like as follows:

{
  msg: "OK"
  status: 200
  data: <your data>
  pageDetails: <page details if you return Page from controller>
}

RestResponse static contructors:

  • RestResponse ok(Object body)
  • RestResponse ok(Object body, PageDetails pageDetails)
  • RestResponse empty(String message, HttpStatus status)
  • RestResponse of(String message, HttpStatus status, Object data)
  • RestResponse of(String message, HttpStatus status, Object data, PageDetails pageDetails)

Every output will be wrapped into RestResponse see this issue

Response wrapping can be disabled for specific endpoinds by using @DisableWrapping annotation on method.

Example application with response wrapping

@SpringBootApplication
@EnableResponseWrapping
public class MySpringBootApplication {

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

  @GetMapping("/wrap-pojo")
  public MyPojo wrapResponse() {
    MySpringBootApplication.MyPojo myPojo = new MyPojo("Jakub", "Pomykala");
    return myPojo;
  }
  
  @Autowired
  private MyPojoRepository myPojoRepository;

  @GetMapping("/wrap-pojo-page")
  public Page<MyPojo> wrapPageResponse() {
    Page<MyPojo> myPojos = myPojoRepository.findAll();
    return myPojos;
  }
  
  public class MyPojo {
    private String firstName;
    private String lastName;
    // getters and setters
  }
}

@EnableCORS annotation

This annotation adds filter which handles CORS requests.

Example application.yml configuration for CORS

spring-hoc:
  cors:
    allow-credentials: true
    allowed-origins:
      - "https://my-frontend-application.com"
      - "https://jpomykala.com"
    allowed-methods:
      - GET
      - POST
      - PATCH
      - DELETE

This properties are optional.

By default CORS will accept all origins, all HTTP methods and all popular headers.

Example application with CORS filter

@SpringBootApplication
@EnableCORS
public class MySpringBootApplication {

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

}

Contribution

Would you like to add something or improve source? Create new issue, let's discuss it

  • If in doubt, please discuss your ideas first before providing a pull request. This often helps avoid a lot of unnecessary work. In particular, we might prefer not to prioritise a particular feature for another while.
  • Fork the repository.
  • The commit message should reference the issue number.
  • Check out and work on your own fork.
  • Try to make your commits as atomic as possible. Related changes to three files should be committed in one commit.
  • Try not to modify anything unrelated.

Source: https://github.com/jOOQ/jOOQ

More

License

GNU General Public License v3.0