30 Mart 2020 Pazartesi

SpringData JpaRepository ile @Query ve Join + Where In Clause - OneToMany Tarzı İlişkilerde Kullanılır

Giriş
In clause parent child ilişkisi varsa parent tarafına uygulanır.

Örnek
Şöyle yaparız.
public interface FileRepository extends CrudRepository<FileEntity, UUID> {
  @Query("SELECT f FROM FileEntity f JOIN MetadataEntity m on f.id = m.file_id
    WHERE (m.key, m.value) IN (:metadataKeyValue)")
  List<FileEntity> findAllByMetadataContains(@Param("metadataKeyValue")
    Map<String,String> metadataKeyValue);
}
Örnek
Elimizde şöyle bir kod olsun. Bu kod in clause seçimini child tarafına uygulamaya çalışıyor ancak beklenen sonucu vermez.
interface ParentRepo extends JpaRepo<Parent,Integer> {
  @Query("SELECT p FROM Parent p JOIN p.children c WHERE p.id = :parentId ando
          c.id IN(:childIds")
  Parent getParentByIdAndChildIds(int parentId, List<Integer> childIds)
}
Açıklaması şöyle.
My expectation is that calling

parentRepo.getParentByIdAndChildIds(1, Arrays.asList(1,2,3))

will return the parent object with only 3 child entities attached, but instead, I get ALL of the children (i.e. children with ids from 1-10).
Belki sadece child'lara erişmek için şöyle yaparız.
interface ChildRepository extends JpaRepository<Child, Integer> {
  @Query("SELECT c FROM Child c WHERE c.parent.id = :parentId and c.id IN(:childIds)")
  List<Child> getParentByIdAndChildIds(int parentId, List<Integer> childIds)
}

SpringMVC RestTemplate postForEntity metodu - Form veya JSON Post Eder

Giriş
Http Post ile belirtilen sınıfı gönderir. 
- Birinci paramtre hedef url
- İkinci parametre data + header bilgisi içeren HttpEntity nesnesi
- Üçüncü parametre döndürülecek sonuç nesnesinin T tipidir. Yani Sonuç ResponseEntity<T> tipindendir. Dönüş tipi ResponseEntity<MsToken>, ResponseEntity<String> gibi bir şey olabilir

Örnek - Form Post Etmek
Login olmak için şöyle yaparız. Data MultiValueMap içine doldurulur. Dönüş tipi String
HttpHeaders httpHeaders = new HttpHeaders(); //Headers
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED_TYPE);
httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

MultiValueMap<String,Object> parameters = new LinkedMultiValueMap<> (); //Data
parameters.add("username",username);
parameters.add("password",password);
parameters.add("remember-me",true);

HttpEntity<MultiValueMap<String,Object>> httpEntity = new HttpEntity (parameters,httpHeaders);
RestTemplate restTemplate = new RestTemplate();
try{
  ResponseEntity<String> responseEntity = restTemplate.postForEntity ("http:.../login",httpEntity,String.class);
  HttpHeaders header = responseEntity.getHeaders();
  ...
} catch(RestClientException ex){
  ...
}
Örnek - Form Post Etmek
Şöyle yaparız
private MsToken getToken() { // create client final RestTemplate restTemplate = new RestTemplate(); // prepare header final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); // prepare form data final MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); map.add("grant_type", "client_credentials"); map.add("client_id", appId); map.add("client_secret", appPassword); map.add("scope", "https://api.botframework.com/.default"); // prepare request final HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map,headers); // execute call final ResponseEntity<MsToken> response = restTemplate .postForEntity(MS_LOGIN_URL, request, MsToken.class); return response.getBody(); }
Örnek - MULTIPART_FORM_DATA Post Etmek
Şöyle yaparız. Data MultiValueMap içine doldurulur
public void postData(String firstname, String lastname, String fileName,
byte[] fileContents) {

  HttpHeaders headers = new HttpHeaders();
  // Set Content Type to multipart/form-data
  headers.setContentType(MediaType.MULTIPART_FORM_DATA);

  MultiValueMap<String, Object> data = new LinkedMultiValueMap<>();
  try {
    // Put form data
    data.add("firstname", firstname); //1
    data.add("lastname", lastname);   //2

    // Put image data
    ByteArrayResource fileData = new ByteArrayResource(fileContents) {
      // This override is required because the default method returns null.
      @Override
      public String getFilename() {
return fileName;
      }
    };
    HttpHeaders parts = new HttpHeaders();
    final HttpEntity<ByteArrayResource> imageEntity = new HttpEntity<>(fileData, parts);
    data.add("image", imageEntity); //3

    // POST form data
    HttpEntity<MultiValueMap<String, Object>> requestEntity =
new HttpEntity<>(data, headers);
    restTemplate.postForEntity(applicationProperties.getDocumentUploadUri(),
requestEntity, String.class);

  } catch (Exception e) {
    e.printStackTrace();
  }
}
Örnek - JSON Post Etmek
Boş bir json post göndermek için şöyle yaparız. Burada ResponseEntity<String> olarak kodladık. Karşı taraf ise boolean dönüyor. ResponseEntity nesnesinin body metodu "true" veya "false" değeri taşır.
String destinationPort = "8090";

RestTemplate restTemplate = new RestTemplate();

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<String> entity = new HttpEntity<> (httpHeaders);

String url ="http://localhost:{port}/foo/bar"
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url,entity,
  String.class,destinationPort);
if (responseEntit.getStatusCode() == HttpStatus.OK){
  ...
}
Bu kod @RequestParam veya @RequestBody verisi göndermez. Şu kodu tetikler
@PostMapping(value="bar")
public boolean bar(){ 
...
}
Aynı şeyi exchange() ile yapmak isteseydik şöyle yapardık
ResponseEntity<String> responseEntity = restTemplate.exchange(url,HttpMethod.POST,entity,
  String.class,destinationPort);

16 Mart 2020 Pazartesi

SpringSecurity OAuth2RestTemplate Sınıfı

constructor
Şöyle yaparız.
ClientCredentialsResourceDetails oauthDetails = new ClientCredentialsResourceDetails();
oauthDetails.setClientId("test");
oauthDetails.setClientSecret("test");
oauthDetails.setAccessTokenUri("https://test/auth/oauth/token");
oauthDetails.setGrantType("client_credentials");

List<String> scopes = new ArrayList<>();
scopes.add("read");
oauthDetails.setScope(scopes);

new OAuth2RestTemplate(oauthDetails);
exchange metodu
Şöyle yaparız.
try {
  return oAuth2RestTemplate.exchange(url, HttpMethod.GET, entity, Resource.class);
} catch (OAuth2AccessDeniedException ex) {
  ...
} catch (HttpClientErrorException ex) {
  ...
} catch (PolarisClientConfigurationException ex) {
  ...
}

11 Mart 2020 Çarşamba

SpringData DataSourceTransactionManager Sınıfı

Giriş
PlatformTransactionManager arayüzünden kalıtır.

constructor - DataSource
Örnek
Eğer bean'e isim vereceksek "transactionManager" demek gerekir. Şöyle yaparız
@Bean(name = "transactionManager")
public PlatformTransactionManager creatTransactionManager(DataSource  dataSource) {
  return new DataSourceTransactionManager(dataSource);
}
Örnek
Şöyle yaparız.
@Configuration
public class PersistenceJPAConfig {
  @Bean
  public DriverManagerDataSource createDataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    //dataSource.set ... DB stuff here
    return dataSource;
  }

  @Bean 
  public PlatformTransactionManager transactionManager(   ){
    DataSourceTransactionManager transactionManager =
      new DataSourceTransactionManager(createDataSource());
    return transactionManager;
  }
}
Örnek
Şöyle yaparız. DataSource olarak DriverManagerDataSource kullanılabilir.
@Configuration
@Import(DatabaseProperties.class})
public class DatabaseConfiguration {


  @Bean
  public DataSource dataSource(DatabaseProperties properties) {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl(properties.url);
    dataSource.setUsername(properties.username);
    dataSource.setPassword(properties.password);
    dataSource.setDriverClassName(properties.driverClassName);

    return dataSource;
  }

  @Bean
  public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
  }

}