spring-higher-order-components
spring-higher-order-components copied to clipboard
⚡️ Preconfigured components to speedup Spring Boot development
Boilerplate components for Spring Boot.
- [x] E-mail sending with step builder
- [x] Request logging
- [x] Files uploading to Amazon S3
- [x] Response wrapping (works with Swagger / SpringFox!)
- [x] Easy to use CORS filter
- [ ] Rate limiter (in progress)
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
Used by
- Translate your e-mails
- Manage translations in Java Proprties
- Get started with localization API
- Translation management
@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 invokesendEmail(EmailRequest)
. - Publish
EmailRequest
usingApplicationEventPublisher
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