16 Şubat 2023 Perşembe

SpringBoot DataSource Yaratma

1. application.properties

2. DataSourceBuilder kullanılabilir

3. DataSource arayüzü gerçekleştirilebilir. Ama bence bu saçma olur

4. JNDI InitialContext sınıfı kullanılarak DataSource elde edilebilir. 

14 Şubat 2023 Salı

SpringSecurity OAuth2 Authorization Server Gerçekleştirimi

Gradle
Şu satırı dahil ederiz
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:1.0.0'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
1. OAuth2AuthorizationServerConfiguration Bean tanımla
Şöyle yaparız
import org.springframework.security.oauth2.server.authorization.config.annotation
.web.configuration.OAuth2AuthorizationServerConfiguration; @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SecurityFilterChain authServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); return http.build(); }
2. RegisteredClientRepository Bean Tanımla
Şöyle yaparız
import org.springframework.security.oauth2.server.authorization.client
  .InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;


@Bean
public RegisteredClientRepository registeredClientRepository() {
  RegisteredClient registeredClient 
    = RegisteredClient.withId(UUID.randomUUID().toString())
    .clientId("oauth-client")
    .clientSecret("{noop}oauth-secret")
    .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
    .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
    .scope(OidcScopes.OPENID)
    .scope("articles.read")
    .build();
  return new InMemoryRegisteredClientRepository(registeredClient);
}
3. JWT Decoder Tanımla
Şöyle yaparız
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
    return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
Public ve private key yaratmak şöyle
@Bean
public JWKSource<SecurityContext> jwkSource() throws NoSuchAlgorithmException {
    RSAKey rsaKey = generateRsa();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}

private static RSAKey generateRsa() throws NoSuchAlgorithmException {
    KeyPair keyPair = generateRsaKey();
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    return new RSAKey.Builder(publicKey)
      .privateKey(privateKey)
      .keyID(UUID.randomUUID().toString())
      .build();
}

private static KeyPair generateRsaKey() throws NoSuchAlgorithmException {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    return keyPairGenerator.generateKeyPair();
}
4. AuthorizationServerSettings Bean Tanımla
Şöyle yaparız
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
    return AuthorizationServerSettings.builder().build();
}
Token almak için şöyle yaparız
curl -X POST 'http://localhost:9090/oauth2/token?grant_type=client_credentials' \
  --header 'Authorization: Basic b2F1dGgtY2xpZW50Om9hdXRoLXNlY3JldA=='
Burada Basic'ten gelen string base64 encoded. Açılmış hali şöyle
oauth-client:oauth-secret
Gelen cevap şöyle
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 299
}



9 Şubat 2023 Perşembe

SpringCloud AWS S3

Maven
Şöyle yaparız
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.awspring.cloud</groupId>
            <artifactId>spring-cloud-aws-dependencies</artifactId>
            <version>3.0.1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
Sonra şöyle yaparız
<dependencies>
  <dependency>
    <groupId>io.awspring.cloud</groupId>
    <artifactId>spring-cloud-aws-starter-s3</artifactId>
  </dependency>
</dependencies>
application.properties
Açıklaması şöyle
There are two ways to communicate with the S3 bucket.

1. Path style URLs.
2. Virtual Hosted style URLs.

The path style URLs were the older mechanism which used the format https://s3.region-code.amazonaws.com/bucket-name.

While the virtual hosted URL uses the format https://bucket-name.s3.region-code.amazonaws.com

The path style URLs will soon be deprecated and LocalStack already supports the virtual hosted style URLs by default.
Örnek
Şöyle yaparız.
spring:
  cloud:
    aws:
      s3:
        endpoint: http://s3.localhost.localstack.cloud:4566
        region: eu-central-1
      credentials:
        access-key: none
        secret-key: none
      region:
        static: eu-central-1
Örnek
Şöyle yaparız. Bizim için bir tane AmazonS3  bean yaratılır
spring.cloud.aws.credentials.access-key=dummy
spring.cloud.aws.credentials.secret-key=dummy
spring.cloud.aws.s3.region=eu-west-1
Örnek
Şöyle yaparız
@RestController
public class WebController {

  @Value("s3://mybucket/samplefile.txt")
  private Resource s3SampleFile;

  @GetMapping("/data")
  public ResponseEntity<String> getData() {
    try {
      return ResponseEntity.ok(s3SampleFile.getContentAsString(StandardCharsets.UTF_8));
    } catch (Exception e) {
      return ResponseEntity.internalServerError()
                    .body("Could not fetch content");
    }
  }

  @PostMapping("/data")
  public ResponseEntity<String> putData(@RequestBody String data) throws IOException {
    try (OutputStream outputStream = ((S3Resource) s3SampleFile).getOutputStream()) {
      outputStream.write(data.getBytes(StandardCharsets.UTF_8));
    }
    return ResponseEntity.ok(data);
  }
}
AmazonS3  Sınıfı
putObject metodu
Örnek
Şöyle yaparız
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;

@Service
@AllArgsConstructor
public class UploadService {

  private final AmazonS3 s3Client;

  public String uploadFile(InputStream file, String fileName) {
    String bucketName = ...;
    s3Client.putObject(bucketName, fileName, file, new ObjectMetadata());
    return s3Client.getUrl(bucketName, fileName).getPath();
  }
}
Unit Test
LocalStackContainer kullanılır

Örnek
Şöyle yaparız
@Testcontainers
@SpringBootTest
@AutoConfigureMockMvc
class SpringBootWithS3ApplicationTests {

  @Autowired
  private MockMvc mockMvc;

  @Value("s3://mybucket/samplefile.txt")
  private Resource s3SampleFile;

  @Container
  private static LocalStackContainer localStackContainer =
    new LocalStackContainer(DockerImageName.parse("localstack/localstack"))
    // to create secrets on startup
    .withCopyFileToContainer(MountableFile.forClasspathResource("script.sh", 0775),
                             "/etc/localstack/init/ready.d/")
    .withServices(LocalStackContainer.Service.S3);

  @BeforeAll
  static void beforeAll() throws IOException, InterruptedException {
    System.setProperty("spring.cloud.aws.s3.endpoint",
      "http://s3.localhost.localstack.cloud:" + localStackContainer.getMappedPort(4566));
    System.setProperty("spring.cloud.aws.s3.region", "eu-central-1");
    System.setProperty("spring.cloud.aws.credentials.access-key", "none");
    System.setProperty("spring.cloud.aws.credentials.secret-key", "none");
  }
 ...
}




6 Şubat 2023 Pazartesi

SpringCache CompositeCacheManager Sınıfı

Örnek
Şöyle yaparız
@Configuration
class MyCachingConfiguration {

  @Bean
  RedisCacheManager cacheManager() {
    // ...
  }

  @Bean
  HazelcastCacheManager hazelcastCacheManager() {
    // ...
  }

  @Bean
  CompositeCacheManager compositeCacheManager(RedisCacheManager redis, 
    HazelcastCacheManager hazelcast) {
    return new CompositeCacheManager(redis, hazelcast);
  }
}

SpringBoot Banner Kullanımı

Giriş
Spring açılırken şu çıktıyı alırız.. 
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.2.RELEASE)
1. Banner Metnini Değiştirmek
Eğer bu çıktı yerine başka bir şey koymak istersek src/main/resources/banner.txt dosyası yaratılabilir.
Örnek
Şöyle yaparız
#################################################
#             Spring Kafka Demo                 #
# author: mmarcosab                             #
# creation date: 15/01/2023                     #
# repo: https://github.com/mmarcosab/kafka-demo #
#################################################
2. Başka Bir Banner Dosyası Kullanmak
Eğer başka bir yerdeki banner dosyamızı kullanmak istersek şöyle yaparız

spring.banner.location=classpath:banner.txt
3. Banner Olarak Resim Kullanmak
src/main/resources/banner.gif isimli bir dosya yaratılabilir
Örnek
Eğer farklı bir gif dosya kullanmak istersek şöyle yaparız. Gerekiyorsa resme ait genişlik vs. gibi özellikler de atanabilir
spring.banner.image.location=

# Optional
spring.banner.image.width=
spring.banner.image.height=
spring.banner.image.margin=
spring.banner.image.invert=
4. Banner'ı Kapatmak
SpringApplicationBuilder sınıfı kullanılır. Bu sınıf Harici Wildfly, Tomcat Varsa Kullanılır

Örnek
Şu satırı dahil ederiz.
import org.springframework.boot.Banner.Mode;
Şöyle yaparız.
SpringApplicationBuilder builder = ...;
builder.application().setBannerMode(Mode.OFF);
Örnek
Şöyle yaparız.
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  application.application().setBannerMode(Mode.OFF);
  return application.sources(SpringApplicationBuilder.class);
}

30 Ocak 2023 Pazartesi

JobRunr Kullanımı

Giriş
JobRunr, Quartz üzerine inşa edilmiş bir kütüphane. Açıklaması şöyle
JobRunr requires a datastore to store the jobs and its metadata, ...
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>com.jobrunr</groupId>
  <artifactId>jobrunr-spring-boot-starter</artifactId>
  <version>5.3.3</version>
</dependency>
application.properties
Örnek
Şöyle yaparız
jobrunr.enabled=true

org.jobrunr.dashboard.enabled=true 
org.jobrunr.dashboard.port=8000
Örnek
Şöyle yaparız
org.jobrunr.background-job-server.enabled=true
org.jobrunr.dashboard.enabled=true
Monitoring jobs
Açıklaması şöyle
JobRunr provides a dashboard that allows you to monitor the status of your jobs. You can access the dashboard by navigating to http://localhost:8000/dashboard in your browser.
1. Fire And Forget Job
enqueue metodu kullanılır  Açıklaması şöyle
These jobs are executed once, and the result is not returned to the caller. This is useful for tasks that don’t require any feedback or response from the job. You can create a fire-and-forget job using the BackgroundJob.enqueue() method, which accepts a lambda expression as a parameter. 

2. Scheduled Job
schedule metodu kullanılır. Açıklaması şöyle
These jobs are executed at a specified time or interval. You can create a scheduled job by using the BackgroundJob.schedule() method, and it accepts a lambda expression, or you can inject an instance of a class.
Örnek
Şöyle yaparız
@Service
public class MyJobs {

  private final JobScheduler jobScheduler;

  @Autowired
  public MyJobs(JobScheduler jobScheduler) {
    this.jobScheduler = jobScheduler;
  }

  @Scheduled(cron = "1 1 19 * * ? *")
  public void scheduleJob() {
    jobScheduler.schedule("once at 5pm", () -> doSomething());
  }
}
3. Recurring jobs
 Açıklaması şöyle
These jobs are executed on a recurring basis. You can create a recurring job using the BackgroundJob.scheduleRecurringly() method, which accepts a cron expression or a Cron object.
4. Adding loggers and progress bars
Açıklaması şöyle
Loggers: JobRunr supports logging, allowing you to log messages from your background jobs. You can add loggers by using the JobContext.logger() method. You can easily inject JobContext it into your background jobs by adding it as a parameter to your lambda expression.
Örnek
Şöyle yaparız
BackgroundJob.enqueue(() -> myService.doWork(JobContext.Null))

// Actual implementation
public class MyService {
    public void doWork(JobContext jobContext) {
        jobContext.logger().info("Hello from JobRunr!");
    }
}
Açıklaması şöyle
Progress bars: You can report the accurate progress of your background jobs using the JobContext.progress() method. The progress bar is visible in the JobRunr dashboard, which will help users understand the status of their jobs. progressBar is available as part of the same JobContext object, so we can use it the same way as the logger.
Örnek
Şöyle yaparız
public class MyService {
  public void doWork(JobContext jobContext) {
    JobDashboardProgressBar progressBar = jobContext.progressBar(1000);
    for(int i = 0; i < 1000; i++) {
      // or use progressBar.setValue(i) to set the value directly
      progressBar.increaseByOne(); 
    }
  }
}
5. Deleting jobs
Açıklaması şöyle
Sometimes, you may want to delete the scheduled or recurring job. You can do this by using the BackgroundJob.delete() method. 
Örnek
Şöyle yaparız
JobId jobId = BackgroundJob.<EmailSender>enqueue(x -> x.doWork());
BackgroundJob.delete(jobId);