restful etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
restful etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

JAX-RS (ACCESSING CONTEXT INFORMATION)

      Bu yazımızda @context ek açıklamasının bizlere sunduğu içerik bilgilerini inceleyeceğiz.

Injecting Application

   İlk olarak application'dan başlıyoruz.Burada ApplicationConfig classımızda extends ettiğimiz Application classındaki getProperties methodunu override ederek kaynak sınıfımıza enjekte edeceğiz.Bu sayede kaynak sınıflarımızı ApplicationConfig class'ımızdan kontrol edebiliriz.Şimdi bunu basitçe nasıl yapabileceğimize bakalım.


import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application {
@Override
public Map<String,Object> getProperties(){
Map<String,Object> map=new HashMap<>();
map.put("KEY_MAX_ORDER_LIMIT", "100");
return map;
}
}
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
public class OrderClient {
public static void main(String[] args) throws Exception {
Client client = ClientBuilder.newBuilder().build();
WebTarget target =
client.target("http://localhost:8080/orders");
Response response = target.request().get(Response.class);
String responseString = response.readEntity(String.class);
System.out.println("response: " + responseString);
}
}
view raw Client hosted with ❤ by GitHub
import java.util.Map;
import java.util.stream.Collectors;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
@Path("/orders")
public class OrderResource {
@GET
public String getAllOrders(@Context Application app) {
Map<String, Object> properties = app.getProperties();
String props = properties.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("\n"));
System.out.println(props);
return properties.get("KEY_MAX_ORDER_LIMIT").toString();
}
}
view raw Resource hosted with ❤ by GitHub
Gördüğünüz gibi,böylece ApplicationConfig sınıfımızda yaptığımız bir değişiklik kaynak sınıfımızı da etkileyecek.Şimdi de browser ve server çıktılarına bakalım.


Injecting UriInfo

        Aynı şekilde UriInfo arayüzümüzdeki fonksiyonların kullanımına ve bunların yine aynı şekilde server'ımızda tutulan log'una bakalım.




Injecting HttpHeaders



Umarım faydalı olmuştur.Bir sonraki yazımızda görüşmek üzere.

JAX-RS (ABORTING FILTER)

     Bu yazımızda filter konusuna devam ediceğiz.Bu seferde kaynak sınıfımız için yazdığımız bir filter'ımızı bazı koşullarda kullanması,bazı koşullarda ise kullanmaması için bir filter daha yazacağız.Bir süzgeç düşünün ve orada portakal suyunu çekirdeklerinden süzüp içeceksiniz.İşte portakalın çekirdekleri ilk yazdığımız filter'a takılıyor dolayısıyla ikinci yazdığımız filterda(mide) bunu kullanmıyor. :).Burada ilk filter çekirdeği görünce,ikinci filter'ı iptal ediyor.Mesela gelen isteklerin veya herhangi bir bilginin log'lanmasını istemediğimiz zaman uygulayabiliriz.Şimdi kodlarımıza bakıp daha iyi anlayalım.


import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application {
}
view raw G1 hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
return "dummy-response for " + path;
}
}
view raw G2 hosted with ❤ by GitHub
@Priority(1)
@Provider
public class InvalidRequestFilter implements ContainerRequestFilter{
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Response resForInvalidRequest = kontrol(requestContext);
if(resForInvalidRequest!=null)
requestContext.abortWith(resForInvalidRequest);
}
private Response kontrol(ContainerRequestContext requestContext){
UriInfo uriInfo=requestContext.getUriInfo();
String path=uriInfo.getPath();
if(path.equals("orders/history")){
String msg = String.format("The feature is not yet supported: %s%n", path);
CacheControl cc=new CacheControl();
cc.setNoStore(true);
Response response=Response.status(Response.Status.NOT_IMPLEMENTED)
.cacheControl(cc)
.entity(msg)
.build();
return response;
}
return null;
}
}
view raw G3 hosted with ❤ by GitHub
import java.io.IOException;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
@Priority(2)
@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- request info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- response info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
System.out.println("HEADERS:");
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw G4 hosted with ❤ by GitHub
Kodlarımızda gördüğünüz gibi.InvalidRequestFilter sınıfımızda yazdığımız kontrol methodunda gelen isteğe göre değer döndürülüyor.Sınıf adı Ingilizce metod Türkçe ne biçim iş yapıyorsun diyebilirsiniz :) fakat kodlar buradaki sayfaya ait ve ben bu kodları yazarken bazı yerlerde ufak oynamalar yapıyorum.Şimdi de çıktımıza bakalım. GET/orders/history isteği hariç diğer tüm istekler sunucumuzda kayıt ediliyor.Aşağıdaki çıktılarda gördüğünüz gibi.


Umarım faydalı olmuştur.Görüşmek üzere.

JAX-RS (FILTER BINDING & DYNAMIC FILTER BINDING)

     Herkese merhaba.Bu yazımızda da yine filter konusunda yazacağımız filter sadece belli kaynak fonksiyonlarına özel olacak.Bunu yaparken ilk defa kendi açıklamamızı oluşturacağız.Daha sonra yazdığımız filter ve kullanacağı kaynak fonksiyon,sınıf,interface veya her neyse,bu açıklama ile işaretlenecek.Binding olayıda tam da burada karşımıza çıkıyor.Türkçe anlamıyla bağlayıcı olan bu kelimenin görevi anlaşılacağı gibi adından geliyor.Gördüğünüz gibi filter ile belli bir kaynağı birbirine bağlayacak.Ek açıklamamızı (Annotation) kodlarken satırlarımızı tek tek açıklayacağız.Şimdi kodlama kısmına geçelim.Üzerinde duracağımız tek yer annotation'ın oluşturulduğu yer.Yazdığımız bu ek açıklama ile bağlayacağımız yerleri işaretlememiz gerekiyor.Kodlar üzerinden devam edelim.



import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.NameBinding;
@NameBinding
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Logged {
}
view raw Gokhan hosted with ❤ by GitHub
Şuan logged adında bir annotation oluşturduk.@target açıklaması yazdığımız logged açıklamasının nerelerde kullanılabileceğini belirtiyor.TYPE ve METHOD birlikte kullanılmış.Bunun anlamı yazdığımız annotation hem fonksiyonlar üzerinde hem de sınıf,interface,enum gibi yapılarda çalışabilir.Bir sonraki satırda ise @Retention açıklamasında bu yazdığımız açıklamaya hangi zamanda erişilsin.Bu değerin varsayılanı RetentionPolicy.CLASS'tır.Burada kullanılan RUNTIME ise bu açıklamaya sadece çalışma zamanında erişim vardır anlamındadır.Bu da java da Java Reflection API tarafından yapılır.Buradan araştırabilirsiniz.Şimdide kodlarımızın geri kalanına bakıp programımızı derleyelim.
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
@Logged
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/customers")
public class MyResource {
@GET
public String getAllCustomers() {
System.out.println("in getAllCustomers()");
return "dummy-response for all customers";
}
@Logged
@GET
@Path("{id}")
public String getCustomerById(@PathParam("id") String id) {
System.out.println("in getCustomerById()");
return "dummy-response for customer " + id;
}
}
view raw Gokhan1 hosted with ❤ by GitHub
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application{
}
view raw Gokhan2 hosted with ❤ by GitHub


Çıktımız ise şu şekilde olacak.Sadece GET/customers gibi bir istekte sunucumuza herhangi bir ek kayıt düşmeyecek.Yani filter kullanılmayacak fakat eğer GET/customers/{id} gibi bir istek gelirse filter kullanılacak.Aşağıdaki görsellerde de çok açık bir şekilde görünüyor.




Bu işi dinamik olarakta gerçekleştirebiliriz.Yani aynı şekilde istediğimiz alanlar için bir filter yazmak istiyorsak,dynamicfeature interfaceni imlement edip gerekli kontrolleri yapamız gerekir.

import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Method;
@Provider
public class FilterRegistrationFeature implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (MyResource.class.isAssignableFrom(resourceInfo.getResourceClass())) {
Method method = resourceInfo.getResourceMethod();
if (method.getName().toLowerCase().contains("order")) {
System.out.println("registering LogFilter");
context.register(new LogFilter());
}
}
}
}
view raw Gokhan hosted with ❤ by GitHub

Umarım faydalı olmuştur.Sağlıcakla kalın.

JAX-RS (FILTER PRIORITIES)

    Bu yazımızda da bir önceki yazımızda olduğu gibi filter yazmaya devam edeceğiz.Bu yazımızda bir önceki yazımıza ilaveten bir filter yazmak yerine projemizde birden fazla filter'ı nasıl yazabileceğimize değineceğiz.Burada yardımımıza koşan ek açıklama ise @priorities.Türkçe anlamı öncelik olan bu ek açıklama yazdığımız filter'ları çalışma sırasına göre sıralıyor.Bu ek açıklama aldığı integer parametre ile filter'ları sıralıyor.Şimdi timefilter ve logfilter adında iki filter yazıp bunların hangi sırada çalışacağını belirleyelim.


package com.mycompany.filterpriorities;
import java.io.IOException;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Priority(1)
@Provider
public class TimeFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- TimeFilter request --");
reqContext.setProperty("start-time", System.currentTimeMillis());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- TimeFilter response --");
long startTime = (long) reqContext.getProperty("start-time");
System.out.printf("Time taken for request %s: %s milli secs%n",
reqContext.getUriInfo().getPath(),
System.currentTimeMillis() - startTime
);
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.filterpriorities;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Priority(2)
@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req headers --");
log(reqContext.getUriInfo(), reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res headers --");
log(reqContext.getUriInfo(), resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub
Gördüğünüz gibi iki filter yazıp bunlara sıra verdik.Parametre değeri düşük olan daha önce çalışacak.Şimdi de resource ve applicationconfig sınıfımızı yazıp örneğimizi çalıştıralım.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
System.out.printf("creating response for '%s'%n", path);
return "dummy-response for " + path;
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("")
public class ApplicationConfig extends Application {
}
view raw Gokhan hosted with ❤ by GitHub

Ve programımızı derleyip payara sunucumuzundaki çıktılarımıza göz atalım.




Gördüğünüz gibi önce time filter'ımız daha sonra log filter'ımız çalışıyor.Umarım faydalı olmuştur.Bir sonraki yazımızda görüşmek üzere.

JAX-RS (FILTERS)

         Bu yazımızda filter konusuna değineceğiz.Biz filter'ları gelen request ve giden response mesajlarını kaynak sınıfımıza erişmeden önce kontrol etmek için yazarız.Örnek verecek olursak login sayfamız için bir filter yazarsak gelen request mesajlarını kontrol ettirip bu sonuca göre kaynak sınıflarımıza erişim izni verebiliriz.Bu yazımızda basit olarak gelen her isteği kapsayan bir filter'ı nasıl yazacağımıza bakalım.Yazacağımız filter bir logfilter olup request ve response mesajları payara yerel sunucumuzda log'lanacak.Bir filter yazabilmemiz için ConteinerRequestFilter ve ConteinerResponseFilter interface'lerinden birini veya ikisini implement etmemiz gerekiyor.Şimdi bir kaynak sınıfı ve bir filter sınıfı yazarak konumuzu pekiştirelim.


@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
return "dummy-response for " + path;
}
}
view raw Gokhan hosted with ❤ by GitHub

Kaynak sınıfımız gördüğünüz gibi.Gelen her istek için kullanıcıya gösterilecek mesaj sabit (dummy-response for) olacak.Şimdide gelen mesajları inceleyebilmek için bir filter yazalım.Bu istekler yazdığımız filter'a takılacak ve sunucumuzda log'lanacak.Şimdilik yapılan isteklerde kaynaklarımıza erişim sağlanabiliyor.Bir sonraki yazımızda ise filter'ımızı geçemeyen istekler belirtilen kaynaklara erişemeyecek.

@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req info --");
log(reqContext.getUriInfo(), reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res info --");
log(reqContext.getUriInfo(), resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub


Gördüğünüz üzere request mesajlarımız için ContainerRequestFilter ve response mesajlarımız için de ContainerResponseFilter interface'lerini implement ettik.Bu interface'lerimizde bulunan filter fonksiyonlarını override ettik.Daha sonra bir log fonksiyonu yazarak  server'ımızda görüntülenecek request ve response mesajlarımızın bazı kısımlarını getirdik.Şimdi tarayıcımızdaki ve sunucumuzdaki çıktılar bakalım.



Şimdide oluşacak bir IOException da,log'umuzda tutulacak kayıt'a bakalım.Girilen % karakterinin oluşturduğu bir exceptionda payara serverımızda aşağıdaki şekilde loglanmış.




Umarım faydalı olmuştur.




JAX-RS (CONTEXT PROVIDER)

    Bu yazımızda daha önce de bahsettiğimiz kaynak sağlayıcılarını nasıl kullanacağımızı öğreneceğiz.Bu sağlayıcılar kaynak sınıflarımıza bir bağlam nesnesi sunar.Bu cümleyi kodlarımızı inceledikten sonra çok daha iyi anlayacağız.



package com.mycompany.contextprovider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class MyContextResolver implements ContextResolver<MyContext> {
private MyContext context=new MyContextImpl();
@Override
public MyContext getContext(Class<?> type){
if(type == String.class)
return context;
return null;
}
private static class MyContextImpl implements MyContext<String>{
@Override
public String get(String key){
return "a context value for key = "+key;
}
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.contextprovider;
public interface MyContext<T> {
T get(String key);
}
view raw Gokhan hosted with ❤ by GitHub
       Sağlayıcımızdan başlayalım.Öncelikle MyContext(içerik) adında bir generic interface oluşturup get fonksiyonumuzu tanımladık.Daha sonra MyContextResolver (içerik çözümleyici) sınıfımızı oluşturup @Provider ek açıklaması ile işaretleyip ContextResolver<T extends object> interface'imizi implement ettik.Daha sonra bu sınıfımız içerisinde bulunan ve yazdığımız MyContext sınıfımızı implement eden MyContextImpl sınıfımızı yazdık.Type'ımızı String olarak belirlediğimiz için override edilmesi gereken fonksiyonumuzun geri dönüşü tipi String oldu.Aynı şekilde ContextResolver<MyContext> olduğu için ezdiğimiz fonksiyonun geri dönüş tipi MyContext oldu.Bu şekilde sağlayıcıları yazmış olduk.Şimdide kaynak sınıfımıza bakalım.
package com.mycompany.contextprovider;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Providers;
@Path("/")
public class MyResource {
@GET
@Path("{path}")
public String create(@PathParam("path")String path,
@Context Providers providers){
ContextResolver<MyContext> cr=providers.getContextResolver(MyContext.class,MediaType.WILDCARD_TYPE);
MyContext<String> c=cr.getContext(String.class);
String r=c.get(path);
return "response: "+r;
}
}
view raw Gokhan hosted with ❤ by GitHub


 
   

      Kaynak sınıfımızda ise @GET metodu ile kullanıcıdan alınan parametre String path değişkeninde tutulmuş.Daha sonra @Context ek açıklamasıyla Providers interface'inden bir nesne türetilmiş.@Context ek açıklamasını daha ayrıntılı öğrenmek istiyorsanız buraya tıklayınız.Sonraki işlemlerde bildiğimiz klasik işlemler.Bir de WILCARD_TYPE var.WILCARD_TYPE içinde bilinmeyen bir sınıfın nesnelerini tutar.
Çıktımız ise bu şekilde 

http://localhost:8080/ContextProvider/contextprovider
response: a context value for key = contextprovider


GÖRÜŞMEK ÜZERE...



JAX-RS (ENTITY PROVIDERS-YAML)

         Bu yazımızda java nesnelerini YAML formatına veya YAML formatını java nesnelerine dönüştüreceğiz.Herhangi bir dilde yazılmış nesneler,YAML formatında tutulabiliriz.Üstelik YAML configrasyon dosyalarında kullanılan XML veya JSON yerine de tercih edilebilir.YAML formatı insanlar tarafından kolay okunabilmesinin yanında kolaylıkla yazılabilir.Şimdi entity provider'ı nasıl kullanacağımıza ve YAML formatındaki dönüşümleri inceleyelim.Bunun için pom.xml dosyamıza YAML bağımlılığını eklemeliyiz.


Kaynak 
Kaynak
Şekiller de gördüğünüz gibi.Resimlerin üzerine tıklayarak kaynağa gidebilirsiniz.
Şimdi de Java'da yazdığımız kodları adım adım yorumlayalım.

package com.mycompany.yamlentityprovider;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("employees")
public class EmployeeResource {
private static Set<Employee> employees=new HashSet<>();
@PUT
@Consumes("application/yaml")
@Path("/{newId}")
public String create (Employee employee,@PathParam("newId") long newId){
employee.setId(Long.valueOf(newId));
if(employees.contains(employee)){
throw new RuntimeException("Employee with id already exists :"+newId);
}
employees.add(employee);
return "Msg: employee created for id : "+newId;
}
@GET
@Produces(MediaType.TEXT_PLAIN)
public List<Employee> list(){
return new ArrayList<>(employees);
}
@DELETE
public void deleteAll(){
employees.clear();
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.yamlentityprovider;
import java.util.Objects;
public class Employee {
private long id;
private String name;
private String dept;
@Override
public boolean equals(Object o){
if(this==o)return true;
if(o==null || getClass()!=o.getClass())return false;
Employee employee=(Employee) o;
return id==employee.id;
}
@Override
public int hashCode(){
return Objects.hash(id);
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
}
view raw Gokhan hosted with ❤ by GitHub




EmployeeResource ve Employee sınıflarımızda kayda değer birşey yok.Daha önce öğrendiğimiz ek açıklamalar ile basit bir servis yazılmış.Dikkat edilecek tek yer, @Consume("application/yaml") olarak belirtilmiş.
package com.mycompany.yamlentityprovider;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Scanner;
import org.yaml.snakeyaml.Yaml;
@Provider
@Consumes({"application/yaml", MediaType.TEXT_PLAIN})
@Produces({"application/yaml", MediaType.TEXT_PLAIN})
public class YamlEntityProvider<T> implements MessageBodyWriter<T>, MessageBodyReader<T> {
@Override
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return true;
}
@Override
public T readFrom(Class<T> type, Type genericType, Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
Yaml yaml = new Yaml();
T t = yaml.loadAs(toString(entityStream), type);
return t;
}
public static String toString(InputStream inputStream) {
return new Scanner(inputStream, "UTF-8")
.useDelimiter("\\A").next();
}
@Override
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return true;
}
@Override
public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return -1;
}
@Override
public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream) throws IOException, WebApplicationException {
Yaml yaml = new Yaml();
OutputStreamWriter writer = new OutputStreamWriter(entityStream);
yaml.dump(t, writer);
writer.close();
}
}
view raw Gokhan hosted with ❤ by GitHub









Gördüğünüz gibi YamlEntityProvider<T> adında bir entity class'ımız mevcut.Entity classlarının kullanım amaçlarından biride o sınıfta kullanılacak veri tipinin sabit olmasıdır.Buna bağlı olarak güvelik seviyesi de artıyor.Implement ettiğimiz interface'teki fonksiyonları override etme zorunluluğunuz olduğunu biliyorsunuzdur.İşte bu yüzden bu interface'teki fonksiyonlar override ettik.Bu sınıfın provider olduğu açıklanmış ve @Produces ve @Consumes ile girdi çıktı işlemlerinin formatları belirlenmiş.Override edilmiş fonksiyonlarda okuma,yazma ve kontrol işlemlerini yaptık.Burada javanın input/output sınıfından yararlandık.Client sınıfımızda ise get,put ve delete metodlarımızı deneme amaçlı 3 fonksiyon yazdık.Burada dikkat edilmesi gereken
 yer ise .register(new YamlEntityProvider<>()).Sağlayıcımızı kaydettik,gibi düşünebilirsiniz.Çıktımız ise aşağıda.
Bu yazımın devamı gelecektir.İyi çalışmalar...


JAX-RS (PROVIDERS)

  

      Daha önceki yazılarımızda RESTful web servislerinde  kaynak sınıflarımızı nasıl oluşturacağımızı öğrenmiştik.Bu yazımızdan itibaren ise JAX-RS'teki sağlayıcıları öğreneceğiz.Sağlayıcılar, JAX-RS çalışma alanını genişletmek için kullanılabileceğimiz bir yoldur.JAX-RS'te sağlayıcıları kullanırken @Provider ek açıklamasını kullanacağız.Bu sağlayıcıları 3'e ayrılıyor.

1)Entity Providers(Varlık Sağlayıcıları)
    
    Varlık sağlayıcıları xml,json gibi veri formatların java nesneleri ile iletişimi sağlarlar.Bu sağlayıcılar MessageBodyReader ve MessageBodyWriter interface'lerini implement ederler.Verinin saklanma türü @Consumes ve @Produces ek açıklamalarıyla belirtilmemiş ise sağlayıcılar tüm türleri destekler.

2)Context Providers(İçerik-Ortam Sağlayıcıları)

     İçerik sağlayıcıları ise @Context ek açıklamasıyla erişebilecekleri bağlamları kontrol eder.Bu sağlayıcılar ContextResolver <T> interface'ini implement ederler.


3)Exception Providers(İstisna sağlayıcıları)

   
      Hata sağlayıcıları, Java istisnalarının http response cevaplarına eşler,karşılaştırır ve bizde bu sonuçlara göre değişik şeyler yapabiliriz.Bu sağlayıcılar ise ExceptionMapper<T> interface'ini implement ederler.Bu 3'üde sağlayıcı olduğundan @Provider ek açıklamasını kullanmak zorundadır.



Bir sonraki yazımızda görüşmek üzere.Huzurlu günler...

JAX-RS PROJE-1 (KAN BAĞIŞI)

          Bu yazımızda daha önce öğrendiğimiz ek açıklamaları kullanarak JSF-MySQL ile yazdığımız bir projeye RESTful web servisi yazacağız.Öncelikle projemizden bahsedelim.Projemizin adı kan bağışı.Kan bağışlamak isteyen gönüllü insanlar,bilgilerini sisteme bırakıyorlar.Kan ihtiyacı olan insanlar ise bu insanları bulup onlarla iletişime geçiyor.Yazacağımız servis sayesinde bu uygulamamızı isteyen herkes çok rahat bir şekilde kullanacak(Hastaneler,bağışçılara ihtiyacı olanlar,bağışçı eklemek isteyenler).Ben bu servisi yazarken sql sorgularıyla uğraşarak size hibernate,jpa gibi teknolojileri bilmezseniz ne kadar zorlanacağınızı göstermek için yazacağım. :) Şaka bir yana ben en kısa zamanda ORM araçlarını öğrenmeye başlayacağım.Kan arayan insanlar için GET metodu ile belirli kriterlere göre veya tüm bağışçıları getirtecek,POST metodu ile bağışçılar sisteme kaydolabilecek.Burada öğrendiğimiz diğer açıklamalarıda kullanacağız.Sırasıyla neler yaptığımıza bakalım.Öncelikle projenin bitmediğini belirtmek istiyorum.Her boş zamanımda eklemeler yapacağım.

package com.mycompany.blooddonorswebservice;
import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("/Donors")
public class DonorsService {
DataService d=new DataService();
@GET
public List<Data> getDonors(@QueryParam("country") String country,
@QueryParam("bloodgroup") String bloodgroup){
if(country!=null && bloodgroup!=null)
return d.getDonorsByCountryAndBloodGroup(country,bloodgroup);
else if(country!=null)
return d.getDonorsByCountry(country);
else if(bloodgroup!=null)
return d.getDonorsByBloodGroup(bloodgroup);
else
return d.getAllDonors();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response addDonors(Data data){
return d.addDonor(data);
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.blooddonorswebservice;
public class Data {
int id;
String isim;
String soyisim;
String eposta;
String telefon;
String adres;
String kangrubu;
String sifre;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIsim() {
return isim;
}
public void setIsim(String isim) {
this.isim = isim;
}
public String getSoyisim() {
return soyisim;
}
public void setSoyisim(String soyisim) {
this.soyisim = soyisim;
}
public String getEposta() {
return eposta;
}
public void setEposta(String eposta) {
this.eposta = eposta;
}
public String getTelefon() {
return telefon;
}
public void setTelefon(String telefon) {
this.telefon = telefon;
}
public String getAdres() {
return adres;
}
public void setAdres(String adres) {
this.adres = adres;
}
public String getKangrubu() {
return kangrubu;
}
public void setKangrubu(String kangrubu) {
this.kangrubu = kangrubu;
}
public String getSifre() {
return sifre;
}
public void setSifre(String sifre) {
this.sifre = sifre;
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.blooddonorswebservice;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.Response;
public class DataService {
Connection conn;
public void connect(){
try{
Class.forName("com.mysql.jdbc.Driver");
conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/kanbagisi","root","");
}catch(Exception e){
System.out.println("hata"+e.getMessage());
}
}
public List<Data> getAllDonors(){
connect();
List<Data> donors=new ArrayList<>();
try{
PreparedStatement ps=conn.prepareStatement("Select isim,soyisim,eposta,adres from bilgiler");
ResultSet rs=ps.executeQuery();
while(rs.next()){
Data b=new Data();
b.setIsim(rs.getString("isim"));
b.setSoyisim(rs.getString("soyisim"));
b.setEposta(rs.getString("eposta"));
b.setAdres(rs.getString("adres"));
donors.add(b);
}
}catch(Exception e){
System.out.println("hata"+e.getMessage());
}
return donors;
}
public List<Data> getDonorsByCountry(String country){
connect();
int i=1;
List<Data> donors2=new ArrayList<>();
try{
PreparedStatement ps=conn.prepareStatement("Select isim,soyisim,eposta,adres from bilgiler where adres like %?%");
ps.setString(1,country);
ResultSet rs=ps.executeQuery();
while(rs.next()){
Data co=new Data();
co.setIsim(rs.getString("isim"));
co.setSoyisim(rs.getString("soyisim"));
co.setEposta(rs.getString("eposta"));
co.setAdres(rs.getString("adres"));
donors2.add(co);
}
}catch(Exception e){
System.out.println("hata"+e.getMessage());
}
return donors2;
}
//------------
public List<Data> getDonorsByBloodGroup(String bloodGroup){
connect();
List<Data> donors3=new ArrayList<>();
try{
PreparedStatement ps=conn.prepareStatement("Select isim,soyisim,eposta,adres from bilgiler where kangrubu like %?%");
ps.setString(1,bloodGroup);
ResultSet rs=ps.executeQuery();
while(rs.next()){
Data blo=new Data();
blo.setIsim(rs.getString("isim"));
blo.setSoyisim(rs.getString("soyisim"));
blo.setEposta(rs.getString("eposta"));
blo.setAdres(rs.getString("adres"));
donors3.add(blo);
}
}catch(Exception e){
//
}
return donors3;
}
public List<Data> getDonorsByCountryAndBloodGroup(String country,String bloodgroup){
connect();
List<Data> donors4=new ArrayList<>();
try{
PreparedStatement ps=conn.prepareStatement("Select isim,soyisim,eposta,adres from bilgiler where kangrubu like %?% and adres like %?%");
ps.setString(1,bloodgroup);
ps.setString(2,country);
ResultSet rs=ps.executeQuery();
while(rs.next()){
Data tw=new Data();
tw.setIsim(rs.getString("isim"));
tw.setSoyisim(rs.getString("soyisim"));
tw.setEposta(rs.getString("eposta"));
tw.setAdres(rs.getString("adres"));
donors4.add(tw);
}
}catch(Exception e){
// System.out.println("hata"+e.getMessage());
}
return donors4;
}
public Response addDonor(Data data){
connect();
try{
PreparedStatement ps=conn.prepareStatement("insert into bilgiler(isim,soyisim,eposta,telefon"
+ ",adres,kangrubu,sifre) values(?,?,?,?,?,?,?)");
ps.setString(1,data.getIsim());
ps.setString(2,data.getSoyisim());
ps.setString(3,data.getEposta());
ps.setString(4,data.getTelefon());
ps.setString(5,data.getAdres());
ps.setString(6,data.getKangrubu());
ps.setString(7,data.getSifre());
ps.executeUpdate();
return Response.ok("Başarılı").build();
}catch(Exception e){
System.out.println("hata"+e.getMessage());
}
return Response.status(Response.Status.NOT_IMPLEMENTED).build();
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.blooddonorswebservice;
import java.io.IOException;
import org.codehaus.jackson.map.ObjectMapper;
public class jsonUtil {
private static ObjectMapper mapper;
static{
mapper=new ObjectMapper();
}
public static String convertJavaToJSon(Object object) throws IOException{
String jsonResult="";
try{
jsonResult=mapper.writeValueAsString(object);
}
catch(Exception e){
// System.out.println(e.getMessage());
}
return jsonResult;
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.core.*;
import javax.ws.rs.ApplicationPath;
@ApplicationPath("bloodcenter")
public class ApplicationConfig extends Application{
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.blooddonorswebservice;
import java.io.IOException;
import javax.ws.rs.client.*;
import javax.ws.rs.core.MediaType;
public class ClientApi {
public static void main(String []args) throws IOException{
Client client=ClientBuilder.newClient();
WebTarget t=client.target("http://localhost:8080/bloodDonorsWebService/bloodcenter/Donors");
String response=t.request().
post(Entity.entity(createDonor(),MediaType.APPLICATION_JSON)).toString();
System.out.println(response);
}
public static String createDonor() throws IOException{
Data d=new Data();
d.setIsim("Gokhan");
d.setKangrubu("AB+");
d.setSoyisim("Guzelkokar");
d.setAdres("Iskenderun/HATAY");
d.setTelefon("496496496496");
d.setEposta("ggggg@gmail.com");
d.setSifre("Galatasaray");
String donorJson=jsonUtil.convertJavaToJSon(d);
return donorJson;
}
}
view raw Gokhan1 hosted with ❤ by GitHub

Kodlarımız gördüğünüz gibi.Öncelikle bu kodlar arasında bloğumuzda bulunmayan Jackson var.Jackson kullanarak Java object <-> JSON dönüşümü yaptık.Daha sonra dataservice kısmında sql sorgularımızı çalıştırdık.Projemiz basit olmasına rağmen önemli birkaç eksiği bulunuyor.Bunlardan bir taneside response mesajları.Çünkü herhangi bir sql exception'ini bile ne tür bir response mesajı olacağına karar vermemişiz.Bir dipnot düşmek istiyorum.Siz siz olun exception'larınızı kullanıcıya göstermeyin. :) Bu projeyi arasıra güncelleyeceğim.SAĞLICAKLA KALIN.

JAX-RS (ENTITY PARAMETERS)

       Bu yazımızda post veya put ek açıklamalarını kullanmak için yazacağımız istemci api'sinde Entity sınıfımızı kullanarak XML,JSON veya düz yazı formatındaki verilerimiz post edeceğiz.Kodlarımızın yardımı ile konuyu çok daha iyi anlayacağız.Hadi başlayalım.

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
public class MyClient {
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/EntityParameters/Entity/test1");
String response = target.request()
.post(Entity.entity("test body", MediaType.APPLICATION_XML), String.class);
System.out.println(response);
Client client2 = ClientBuilder.newClient();
WebTarget target2 = client.target("http://localhost:8080/EntityParameters/Entity/test1");
String entity = "<myMsg><id>2</id><msg>hello</msg></myMsg>";
String response2 = target.request()
.post(Entity.entity(entity, MediaType.APPLICATION_XML), String.class);
System.out.println(response);
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/")
public class Resources {
@Path("/test1")
@POST
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public String handle(String entityParam) {
System.out.println(entityParam);
return "entity parameter: " + entityParam;
}
}
view raw Gokhan1 hosted with ❤ by GitHub
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>2.25.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.25.1</version>
</dependency>
</dependencies>
view raw Gokhan2 hosted with ❤ by GitHub




 Bağımlılıkları eklemeyi unutursanız çok sinir bozucu bir hata ile karşılaşırsınız.Aslında ne kadar çok hata ile karşılaşırsanız o kadar iyi öğrenirsiniz.

İYİ ÇALIŞMALAR...

JAX-RS (RESOURCE CONSTRUCTOR)

     Bu yazımızda daha önce gördüğümüz,verileri kullanıcıdan parametre olarak almamıza yarayan @HeaderParam,@CookieParam gibi açıklamaları kaynak class'ımızın yapıcı(constructor) fonksiyonundan alacağız.Kodlar üzerinden devam edelim.Aşağıda gördüğümüz üzere MyResource sınıfımızın yapıcı fonksiyonu global olarak tanımlı değikenlere parametre olarak gelen değişkenleri atıp,handleRequest fonksiyonundan bu değerlere ulaşıyor.Şimdi de yazdığımız kaynak sınıfını client sınıfımız ile kontrol edelim.
import java.net.URI;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("/")
public class MyResource {
private final UriInfo uriInfo;
private int qValue;
private int pathNum;
public MyResource(@QueryParam("test") int qValue,
@Context UriInfo uriInfo,
@PathParam("num") int pathNum
) {
this.pathNum = pathNum;
this.uriInfo = uriInfo;
this.qValue = qValue;
}
@GET
@Path("/test{num:[1,9]{0,1}}")
public String handleRequest() {
URI uri = uriInfo.getRequestUri();
return String.format("response from: %s%n PathNum: %s%n q: %s%n",
uri, pathNum, qValue);
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
public class MyClient {
public static void main(String [] args){
Client client=ClientBuilder.newClient();
WebTarget target=client.target("http://localhost:8080/ResourceConstructor/test9");
String response=target.queryParam("test",496).request().get()+"";
System.out.println(response);
}
}
view raw Gokhan hosted with ❤ by GitHub

Aynı şekilde kurala uygun bir istek yaptığımızda çıktımız yandaki gibi olacaktır.
 Buraya kadar olan yazılarımı gözden geçirip hatalarımı düzeltip güncelleyeceğim.Kodlarımı yazdığım bilgisayarım çok eski olduğundan biraz ağır ilerliyoruz.Kısmet olursa bu hafta bilgisayarımı yenileceğim.Daha sonra  yazılarımızın sayısı hızla artacak.JAX-RS'i bitirip.HttpClient,mikroservisler gibi konular ile devam edeceğiz.Bu arada yetişirse bu yaz'ın sonuna kadar hibernate,jpa,spring mvc gibi JAVA EE teknolojilerini birlikte öğrenip çok iyi projeler geliştireceğiz.Bir sonraki yazımızda görüşmek üzere kendinize iyi bakın.

JAX-RS (SINGLETON RESOURCES)

        Bu yazımızda ApplicationConfig sınıfımızda extends ettiğimiz,Application classında bulunan getSingletons() metodunu override ederek neler yapabileceğimizi inceleyeceğiz.Servisimiz her http isteğinde kaynakları tekrar tekrar oluşturur.Bu varsayılan çalışma şeklidir.Bildiğiniz üzere bazı fonksiyonları (static,final gibi.Bunlar override edilemez) override ederek geçersiz kılıp ihtiyacımıza bağlı olarak değiştirebiliriz.Bu yazımızda da bu kaynakların tekrar oluşmasını önlemek için getSingletons() fonksiyonunu override edeceğiz.Kodlarımızı görünce daha iyi anlayacağız.
import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@ApplicationPath("/")
public class ApplicationConfig extends Application {
@Override
public Set<Class<?>> getClasses(){
Set<Class<?>> set =new HashSet<>();
set.add(MyResource.class);
return set;
}
@Override
public Set<Object> getSingletons(){
Set<Object> set=new HashSet<>();
set.add(new MySingletonResource());
return set;
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/")
public class MyResource {
private int counter;
@GET
@Path("count1")
public void count() {
counter++;
}
@GET
@Path("counter1")
public int getCounter() {
return counter;
}
@GET
@Path("reset1")
public void reset() {
counter = 0;
}
}
view raw Gokhan1 hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/")
public class MySingletonResource {
private int counter;
@GET
@Path("count2")
public void count() {
counter++;
}
@GET
@Path("counter2")
public int getCounter() {
return counter;
}
@GET
@Path("reset2")
public void reset() {
counter = 0;
}
}
view raw Gokhan2 hosted with ❤ by GitHub
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
public class MyClient1 {
public static void main(String[] args) {
getRequest("/reset1", Void.class);
countRequest("/count1");
Integer counter = getRequest("/counter1", Integer.class);
System.out.printf("counter1: %s%n", counter);
getRequest("/reset2", Void.class);
countRequest("/count2");
Integer counter2 = getRequest("/counter2", Integer.class);
System.out.printf("counter2: %s%n", counter2);
}
public static void countRequest(String uri) {
for (int i = 0; i < 10; i++) {
getRequest(uri, Void.class);
}
}
public static <T> T getRequest(String uri, Class<T> responseType) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080" + uri);
return target.request().get(responseType);
}
}
view raw Gokhan3 hosted with ❤ by GitHub


Gördüğünüz üzere iki farklı kaynak sınıfımız ve ApplicationConfig  sınıfımız var.ApplicationConfig'te gördüğünüz set collection'ı,list'in bir benzeri olup verileri herhangi bir index ile tutmaz.İki fonksiyonumuzu override ettik.

counter1: 0
counter2: 10
Çıktımız bu şekilde olacaktır.Client classımızın yaptığı request mesajlarına karşılık ApplicationConfig class'ımızda ezdiğimiz fonksiyonlar :).<T> gelecek olan class'tan sonra şekil alacak.Bir sonraki yazımızda görüşmek üzere.


JAX-RS (COOKIES)

        Bu yazımızda çerezler ile çalışacağız.Çerez,herhangi bir İnternet sitesi tarafından bilgisayara bırakılan bir tür tanımlama dosyası. Çerez dosyalarında oturum bilgileri ve benzeri veriler saklanır.Yani,biz uygulamamız için bir çerez oluşturup bunu response mesajımıza ekleyeceğiz.Bu çerezlerde tarayıcılarda tutulacak.Daha sonra tarayıcıdan bir request mesajı daha gönderilecek olursa bu çerezlerde bu mesajın içinde yer alacak.Bu tekrar eden request istekleri için değişik şeyler yapılabilir.Örneğin siz bir sosyal medya uygulamasına giriş yaptınız.Daha sonra bu platformu kullanan bir uygulamayı kullanmak istediniz.Orada giriş bilgilerinizi tekrar girmenize gerek kalmaz.Bir başka örneğimiz bir bankanın internet bankacılık uygulamasından.Kendi hesabınıza girdikten sonra herhangi bir şekilde sayfanızı yenilediğinizde sizi otomatik olarak çıkışa yönlendiriyor.Şimdi bir cookie oluşturup bunu response mesajımıza ekleyelim.


import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@Path("/")
public class MyResource {
@GET
@Path("test")
public Response getCookie(){
NewCookie cookie1=new NewCookie("myStrCookie","strValue");
NewCookie cookie2=new NewCookie("myDateCookie","2018-06-10");
NewCookie cookie3=new NewCookie("myIntCookie","200");
Response.ResponseBuilder rs=Response.ok("myStrCookie myDateCookie and myIntCookie sent to the browser");
Response r=rs.cookie(cookie1,cookie2,cookie3).build();
return r;
}
view raw jaxrs1 hosted with ❤ by GitHub


Gördüğünüz gibi oluşturduğumuz çerezleri response mesajımıza ekleyip döndürdük.Yalnız dikkat edeceğimiz birkaç nokta var.Çerez adlarımızı belirlerken virgül,noktalı virgül ve boşluk kullanmamalıyız.Çünkü bu karakterleri kodlayacak bir standart mevcut değil.Bu çerezler http response mesajının başlık kısmında Set-Cookie başlığı altında tutulup farklı başlıklar altında sıralanıyor.Çıktı da gördüğünüz gibi.Peki bu çerezlere bir http isteği ile erişmeye çalışırsak nasıl olacak ?Bir de ona bakalım.Yukarıdaki çerezlerimizi birde request mesajı ile görüntüleyelim.

@GET
@Path("test2")
public String readAllCookies(@Context HttpHeaders headers) {
Map<String, Cookie> cookies = headers.getCookies();
String str = cookies.entrySet()
.stream()
.map(e -> e.getKey() + " = " + e.getValue().getValue())
.collect(Collectors.joining("<br/>"));
return str;
}
view raw jaxrs1 hosted with ❤ by GitHub

Şimdi de @CookieParam açıklamasını kullanarak bu çerezler üzerinde işlemler yapalım.Örneğin integer değer olarak gönderdiğimiz çerezi biz long olarak alabilir veya tarihi direct cookie tipinde alıp işleyebiliriz.Kodlarımıza göz atalım.

@GET
@Path("test3")
public String readCookie2(@CookieParam("myDateCookie") Cookie cookie) {
return "Cookie object :" + cookie;
}
@GET
@Path("test4")
public String readCookie3(@CookieParam("myIntCookie") Long aLong) {
return "myIntCookie in Long :" + aLong;
}
view raw jaxrs1 hosted with ❤ by GitHub




Son olarak bu çerezleri bir list aracılığıyla okuyalım.
@GET
@Path("test5")
public Response writeCookies() {
NewCookie cookie1 = new NewCookie("myCookie", "cookieStrVal");
NewCookie cookie2 = new NewCookie("myCookie", "cookieStrVal2");
Response.ResponseBuilder rb = Response.ok(" Multiple values of myCookie"
+ " sent to the browser");
Response response = rb.cookie(cookie1, cookie2)
.build();
return response;
}
@GET
@Path("test6")
public String readCookie4(@CookieParam("myCookie") List<String> list) {
String rv = "List size: " + list.size() +
"<br/>List values:<br/> ";
rv += list.stream()
.collect(Collectors.joining("<br/>"));
return rv;
}
view raw jaxrs1 hosted with ❤ by GitHub


Yazılarımda konuşma dili kullanığım için anlamsız cümleler kurmuş olabilirim.Anlamadığınız yeri yorum kısmından sorabilirsiniz.Konuyu çok iyi bir şekilde öğrendiğimi düşündüğümde videolu anlatım yapmayı düşünüyorum.Bir sonraki yazımızda görüşmek üzere kendinize iyi bakın :)




JAX-RS (REQUEST & RESPONSE HEADERS)

     Herkese merhaba.Bu yazımızda http request ve response mesaj başlıkları üzerinde çalışcağız.Çeşitli kod örnekleri ile paketlerimizin yapısını iyice araştıracağız.Kodlarımızı parça parça yazıp yavaş yavaş anlayarak incelemeye çalışacağız.İşe httpheaders kullanarak tüm başlık mesajlarını çekerek başlayalım.Burada @Context ek açıklamasını kullanacağız.Şimdi de kodlarımıza bakıp,ayrıntılı bir şekilde inceleyelim.


  
@Context ve HttpHeaders kullanarak request mesajımızın başlık bilgilerini görüntüledik.Bunu yaparken key & value mantığında çalışan bir MultivaluedMap tanımladık.Daha sonra bu gelen başlık mesajlarını içine depoladık.Şimdide String str kısmına geldik.Sadece bir satır kodda javanın içinde kaybolup gidebileceğiniz kod parçalarından.Belki de üniversitemizde daha çok oop mantığı öğretildiği için java'nın stream api'sine bakacak fırsat bulamamışdır.Neyse bilmemek değil öğrenmemek ayıptır deyip yolumuza devam edelim :).Bu kod satırımızı sondan başlayarak inceleyelim.Collect tür dönüşümü yapan bir fonksiyon.Burada map bize Stream<> tipinde geri dönüş yapıyor ve bu değeri bir string atmaya çalıştığımız için bu dönüşüm yapılmış.Yani anlayacağınız kod'un sonuna +"" eklemekte bir çözüm.Map ise dönüşüm yapan bir fonksiyon,içerisinde ise lambda expressions kullandık.Lambda expression'ı geriye değer döndüren kod satırı diye düşünübilirsiniz.Bir fonksiyon değil fakat belli parametreler alıp o parametreler ile ilgili değer döndürüyor.Burada aldığı e parametresinin key ve value'sunu döndürüyor.Lambda expression kullanırken bunun 1.8 ve sonrasıdaki source formatında geçerli olduğunu söyleyebilir.Bunu düzeltmek için projenizin properties sekmesinden sources'a gidin ve oradaki source format değerini 1.8 veya daha üstünde bir değere ayarlayın.Stream'e gelecek olursak map stream'in bir işlemi.Stream Api yığınsal veriler üzerinde daha kolay çalışabilmemiz için geliştirilmiş.Collection,diziler vb. gibi.Map gibi kullanabileceğimiz diğer işlemleri burada gördüğünüz siteden alıntı yaparak bir fotoğraf kullanmak istiyorum.Fotoğrafı şimdilik yükleceğim.Kaynakta belirttik.Linkedin üzerinden de yazı sahibinden izin alacağım.İzin vermezse hemen kaldırırız.Yazılarımda alıntı yaptığım yerlerin kaynaklarını belirtmeye çalışırım.Etik olanda bu zaten.Adam o kadar yazmış etmiş,neymiş kopyala yapıştır sonrada ben yaptım :).Öyle olmaz arkadaşlar kimsenin hakkını yemeyelim.Bu arada kodlarımızın buradan olduğunu neredeyse her yazımda belirtmeye çalıştım.Allah var çok iyi örneklendirmiş.Neyse devam edelim.

ve map'teki key & value'ler ile işlem yapabilmemiz için entrySet().Dediğimiz gibi daha sonra da stream ve ilgili metod.Tersten başlayarak değişik bir yorum kattığımı düşünüyorum.Değişik çözümler üreterek daha akılda kalıcı şekilde öğrenmeye ve öğretmeye çalışıyorum.Test2 ile devam edelim.







Bu sefer bir map'e ihtiyaç duymadığımız için bir list kullanarak (Locale sınıf değikenleri) belirli verileri çektik.Test3'e bakalım.


Burada da @HeaderParam ile getirdik.

Önemli yerlere değindiğimizi düşünüyorum.Burada daha çok örnek mevcut.

İYİ ÇALIŞMALAR...




JAX-RS (@MatrixParam ANNOTATION)


      Herkese merhaba.Bu yazımızda @MatrixParam ek açıklamasını öğreneceğiz.Bu annotation daha önce öğrenmiş olduğumuz @QueryParam'a benziyor.Örnek verecek olursak apples?order=random&color=red (@QueryParam) apples;order=random;color=red (@MatrixParam).Görünüş olarak fark bu.Matrix parametleri yolun herhangi bir yerinde olabilir apples;order=random;color=red/10/items gibi.En dikkat çekici farklardan bir tanesi de sorgu parametreleri kaynak olduğundan güvenlik açığı yaratabilir, matrix parametleri ise bir kaynak olmayıp kaynağa başvurma yöntemi olduğundan açık daha azdır.Burada daha fazla bilgi mevcut. Kodlarımıza göz atalım.
package com.mycompany.matrixparamannotation;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.PathSegment;
import java.util.List;
@Path("/")
public class CustomerResource {
@GET
@Path("customers")
public String getCustomers(@MatrixParam("state") String state) {
String info = String.format("resource getCustomers(). state:%s%n", state);
return info;
}
@GET
@Path("{var:customers}/orders")
public String getOrders(@PathParam("var") PathSegment ps) {
String info = String.format("resource getOrders(). Path:%s, MatrixParams:%s%n",
ps.getPath(), ps.getMatrixParameters());
return info;
}
@GET
@Path("{var1:customers}/{var2:orders}/{month}")
public String getMonthOrders(@PathParam("var1") PathSegment customerPs,
@PathParam("var2") PathSegment orderPs,
@PathParam("month") String month) {
String info = String.format("resource getMonthOrders(). Customers Matrix Param: %s," +
" Orders Matrix Param: %s, month :%s%n", customerPs.getMatrixParameters(),
orderPs.getMatrixParameters(), month);
return info;
}
@GET
@Path("testA/{var:.+}")
public String testList(@PathParam("var") List<PathSegment> pathSegmentList) {
String temp = "";
for (PathSegment pathSegment : pathSegmentList) {
temp+= String.format("Path: %s, Matrix Params %s<br/>", pathSegment.getPath(),
pathSegment.getMatrixParameters());
}
String info = String.format("resource testList.<br/> Matrix Param List:<br/> %s<br/>", temp);
return info;
}
}
view raw a.java hosted with ❤ by GitHub


         Arkadaşlar bu konuyu iyi anlatamadığımı düşünüyorum.Biraz rahatsız olduğum için birkaç güne düzgün bir şekilde güncelleyeceğim.İYİ ÇALIŞMALAR..

JAX-RS WADL (Web Application Description Language)

       Bu yazımızda WADL'dan bahsedeceğiz. WADL (Web Application Description Language) restful web servislerimizin kullanımı hakkında bilgiler verir.Servisimizin desteklediği http metodları, fonksiyonları , hangi parametrelerin kullanıldığı vb. şeyleri tutan xml tabanlı bir dökümandır. Buna benzer olarak birde swagger var.Ona başka bir yazımızda değineceğiz. Şimdi bir WADL dökümantasyonunun nasıl oluşturulduğuna göz atmadan önce bu gibi dökümantasyonların biraz güvensiz olduğunu okudum. Bakın bir proje geliştiriyor olabilirsiniz. Tabiki projeyi bitirmek,doğru çalışmasını sağlamak önemlidir ama daha da önemlisi projenizin güvenli olmasıdır. En basitinden kullanıcıdan aldığınız verileri kontrol ettirin. Maalesef her kullanıcının niyeti iyi olmuyor. Ben şimdilik sadece eğitim amaçlı yazılar yazdığım için pek fazla dikkat etmiyorum. İleride geliştireceğim yazılımlarda en dikkat edeceğim konu kuşkusuz güvenlik olacaktır. Etrafımızda binlerce yazılımcı var. Aralarında,  bırakın güvenli kod yazmayı,güvenlik kelimesini bile aklına getirmiyor. Bazen değişik sitelere denk geldiğim oluyor. Heryer sql açığı ile dolu. Tamam açık bırakıyorsunuz da açığınız sql açığı olmasın bari.Aşağıdaki wadl sözleşmesini inceleyelim.Gördüğümüz üzere bize rest servisimiz hakkında bilgiler veriyor.



,
İYİ ÇALIŞMALAR

JAX-RS (@DELETE ANNOTATION)

   Herkese merhaba. Bu yazımızda diğer bir http metodu olan delete bakacağız.Delete'te silme işlemi yapıyor. Bu örneğimizde dikkat edeceğimiz en önemli yer delete ve get requestlerine aynı uriyi verdiğimiz yerdir. Bu çok önemli. Uri'nin içinde http metodlarına ait bilgi bulunmamalıdır.Örnek verecek olursak GET/orders/1 dediğimizde id'si 1 olan siparişi göster,DELETE/orders/1 dediğimizde ise id'si 1 olan siparişi silecek. Bu örneğimizde farklı olarak orderServis adında bir enum oluşturduk. Enumlar kodlarımızın daha okunur olmasını sağlar. Enum yerine class oluşturup bir nesne türetip o nesne ile fonksiyonlara erişebilir veya fonksiyonları static yaparak sınıfımızdan direkt olarak erişebilirdik. Enumlar hakkında daha fazla bilgi için buraya tıklayabilirsiniz. Şimdi kodlarımıza ve çıktılarımıza bakalım.

package com.mycompany.deleteannotation;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Date;
@XmlRootElement
public class Order {
private int id;
private String item;
private int qty;
private Date orderDate;
public Order() {
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", item='" + item + '\'' +
", qty=" + qty +
", orderDate=" + orderDate +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public int getQty() {
return qty;
}
public void setQty(int qty) {
this.qty = qty;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
}
view raw order.java hosted with ❤ by GitHub
package com.mycompany.deleteannotation;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.Collection;
@Path("/orders")
@Produces({MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN})
public class OrderResource {
@GET
public Collection<Order> getOrders() {
return OrderService.Instance.getAllOrders();
}
@DELETE
@Path("{id}")
public boolean deleteOrderById(@PathParam("id") int id) {
return OrderService.Instance.deleteOrderById(id);
}
@GET
@Path("{id}")
public Order getOrderById(@PathParam("id") int id) {
return OrderService.Instance.getOrderById(id);
}
}
view raw orderResource hosted with ❤ by GitHub
package com.mycompany.deleteannotation;
import java.time.*;
import java.util.*;
public enum OrderService {
Instance;
private Map<Integer,Order> orders=new HashMap<>();
OrderService(){
Instant instant = OffsetDateTime.now().toInstant();
for (int i = 1; i <= 5; i++) {
Order order = new Order();
order.setId(i);
order.setItem("item " + i);
order.setQty((int) (1 + Math.random() * 100));
long millis = instant.minus(Period.ofDays(i))
.toEpochMilli();
order.setOrderDate(new Date(millis));
orders.put(i, order);
}
}
public Collection<Order> getAllOrders(){
return new ArrayList<>(orders.values());
}
public boolean deleteOrderById(int orderId) {
return orders.remove(orderId) != null;
}
public Order getOrderById(int id) {
return orders.get(id);
}
}






İYİ ÇALIŞMALAR...


JAX-RS (@HEAD ANNOTATION)

        Bu yazımızda başka bir HTTP'i metodu olan HEAD'ı öğrenip kullanacağız. HEAD metodu ile yapılan istekler bize  yanıt olarak boş döner. Bize sadece http yanıt başlıkları ve durum kodları ile ilgili bilgiler döner. Bu sayede HEAD metodu ile servis sağlayıcı hakkında bilgi alınabilir ya da bir kaynağın varlığı doğrulanabilir. Dediğimiz gibi aslında GET gibi çalışır fakat bize response hakkında bilgi verir.Kodları inceleyelim. ApplicationConfig classımızı paylaşmıyorum. Her projemizde kullandığımızı unutmayalım.
/**
*
* @author gokhan
*/
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@ApplicationPath("app")
public class ApplicationConfig extends Application{
}
import javax.ws.rs.*;
import javax.ws.rs.core.*;
/**
*
* @author gokhan
*/
@Path("/")
public class HeadResource {
@Path("/test")
@HEAD
public Response handle(@QueryParam("param1") String param1) {
System.out.printf("param1: %s%n", param1);
NewCookie c=new NewCookie("deneme","Muslera");
Response r = Response.ok("this body will be ignored").cookie(c)
.header("someHeader", "Value").build();
return r;
}
@Path("/test2")
@GET
public Response handle2() {
NewCookie c=new NewCookie("deneme","Muslera");
Response r = Response.ok("some body content").cookie(c)
.header("someHeader2", "Value2").build();
return r;
}
}
view raw HeadResource hosted with ❤ by GitHub






İYİ KODLAMALAR.

JAX-RS (@PUT ANNOTATION)

    Herkese merhaba.Bu yazımızda bir başka HTTP metodu olan PUT'u öğreneceğiz. Daha önce @GET ve @POST'u öğrenmiştik. Put veri güncellememizi sağlıyor. Bu tip bir request mesajı oluşturduğumuzda güncellemek istediğimiz veri bulunup istenilen değer ile güncelleniyor. Güncellemek istediğimiz veri bulunmaz ise bu veri post ediliyor. Eğer zaten var ise herhangi bir işlem gerçekleşmeyecektir. Bu örneğimizde ise item sınıfımızdaki override ettiğimiz equals ve hashcode fonksiyonları önemlidir. Burada kontrol edilecek verinin hangi tipte olduğu bilinmediği için bu fonksiyonları override ediyoruz. Yani örneğin bir String değişkeninin diyelim ki a,bunun başka bir a'ya eşit olduğunu String sınıfı bilir fakat bizim yazdığımız item sınıfı gelen değişkenin int'mi String'mi olduğunu bilmez ve bilmediği içinde bu put'ta hataya yol açar.Aynı veri tekrar eklenebilir. Web servis kısmımızda ise girilen verilenin hangi formatta olduğunu ve bu verinin list'emizde bulunup bulunmadığını kontrol ettik. Eğer bu veri mevcut ise http 204 kodlu response yok ise bu veriyi ekleyip 201 kodlu response mesajını gönderir. Kodlarımıza ve test çıktımıza bakalım.

Arkadaşlar bu aralar çok fazla çalışıyorum. Bundan şikayetçimiyim,asla değilim. Hepsi hayallerim için. Belki de benim hayallerimin geçtiği yol ile sizin hayalleriniz kesiştiği için yazılarımı takip ediyorsunuzdur. Ne olursa olsun vazgeçmeyin.İnsan beyni herşeyi öğrenecek güçtedir. Ha rakibiniz 4 saatte siz 6 saattemi öğreniyorsunuz. O 12 saat çalışıyorsa siz 24 saat çalışın.Neyse bu arada bu yazılara bakmadan önce Java'nın Collections kütüphanesine bir göz atın. Ve anlamadığınız her satırı araştırın veya sorun.

package com.mycompany.putannotation;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
@ApplicationPath("api")
public class ApplicationConfig extends Application {
}
view raw a1.java hosted with ❤ by GitHub
package com.mycompany.restfulwebservice;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import com.mycompany.putannotation.*;
import java.util.List;
@Path("items")
public class itemRestService {
@Context
private UriInfo uriInfo;
private DataService dt=DataService.getInstance();
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<item> getItems(){
return dt.getItemList();
}
@Path("{sku}")
@PUT
@Consumes(MediaType.APPLICATION_JSON)
public Response createItem(item item, @PathParam("sku") String sku) {
if (dt.itemExists(sku)) {//204
return Response.noContent()
.build();
} else {//201
dt.createItem(item, sku);
return Response.created(uriInfo.getAbsolutePath())
.build();
}
}
@GET
@Path("{sku}")
@Produces(MediaType.APPLICATION_JSON)
public Response getCustomer(@PathParam("sku") String sku) {
item item = dt.getItemBySku(sku);
if (item == null) {
return Response.status(Response.Status.NOT_FOUND)
.build();
} else {
return Response.ok()
.entity(item)
.build();
}
}
}
view raw a2.java hosted with ❤ by GitHub
package com.mycompany.putannotation;
import java.util.ArrayList;
import java.util.List;
public class DataService {
private List<item> itemList = new ArrayList<>();
private static DataService ourInstance = new DataService();
public static DataService getInstance() {
return ourInstance;
}
public void createItem(item item, String sku) {
item itemToStore = new item(sku);
itemToStore.setPrice(item.getPrice());
itemToStore.setName(item.getName());
itemList.add(itemToStore);
}
public boolean itemExists(String sku) {
for (item item : itemList) {
if (item.getSku().equals(sku)) {
return true;
}
}
return false;
}
public List<item> getItemList() {
return itemList;
}
public item getItemBySku(String sku) {
for (item item : itemList) {
if (item.getSku().equals(sku)) {
return item;
}
}
return null;
}
}
view raw a3.java hosted with ❤ by GitHub
package com.mycompany.putannotation;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import java.math.BigDecimal;
@XmlRootElement
public class item {
@XmlAttribute
private String sku;
private String name;
private BigDecimal price;
public item() {
}
public item(String sku) {
this.sku = sku;
}
public String getSku() {
return sku;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
item item = (item) o;
return sku.equals(item.sku);
}
@Override
public int hashCode() {
return sku.hashCode();
}
@Override
public String toString() {
return "Item{" +
"sku='" + sku + '\'' +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
view raw a4.java hosted with ❤ by GitHub





Kendinize iyi bakın.İyi çalışmalar...


JAX-RS (@POST ANNOTATION)

       Herkese merhaba. Bu yazımızda http methodlarından post'un nasıl kullanıldığını göreceğiz.Daha önceki yazılarımızda post'un veri eklemek için kullanıldığını belirtmiştik. Şimdi de farklı formatlar ekleyip farklı formatlarda response mesajlarını getireceğimiz çok güzel bir uygulamayı ele alacağız.Uygulamamızdaki sınıflardan bahsedecek olursak,customer java entity'lerimiz üzerinde işlemler yapmak için,CustomerDataService classımızdan veri ekleyip veri çekeceğiz. Burada javanın util sınıfından faydalanacağız.ClientApp ve ClientUtil classlarımızı ise verilerimizi değişik formatlarda post etmek ve aynı şekilde get etmek için kullanacağız. CustomerWebService classımızda ise belli kurallar çerçevesinde yaptığımız HTTP request metodlarıyla verileri üzerinde işlemler yapacağız. Bu örnek diğerlerine göre biraz daha önemli olduğu için her classımızın fonksiyonlarına ayrı ayrı değinmeye çalışacağım. Hadi başlayalım.

package com.mycompany.client;
import java.util.ArrayList;
import java.util.List;
public class CustomerDataService {
public List<Customer> customerList=new ArrayList<>();
Customer e=new Customer();
public CustomerDataService(){
e.setAddress("Hatay/Antakya");
e.setId("0");
e.setName("Gokhan");
e.setPhoneNumber("15134235322452");
customerList.add(e);
}
private static CustomerDataService ourInstance=new
CustomerDataService();
public static CustomerDataService getInstance(){
return ourInstance;
}
public String addCustomer(Customer customer){
String newId=Integer.toString(customerList.size()+1);
customer.setId(newId);
customerList.add(customer);
return newId;
}
public List<Customer> getCustomerList(){
return customerList;
}
public Customer getCustomerById(String id) {
for (Customer customer : customerList) {
if (customer.getId().equals(id)) {
return customer;
}
}
return null;
}
}


Sınıfımızı incelemeden önce Customer.java adlı sınıfımızın olduğunu ve bu sınıfımızda name,address ve phonenumber adındaki değişkenlerimizin setter ve getter metodlarının bulunduğunu unutmayalım. Bu classımızda verilerimiz list yardımı ile işlenmiş. addCustomer metodumuzda id ile birlikte parametre olarak alınan customer nesnesi customerList'e depolanıyor.newId ise bir nevi veritabanındaki AutoIncrement gibi çalışıyor. getCustomerList fonksiyonumuz bize o listede bulunan tüm değerleri list olarak döndürüyor.Aynı şekilde getCustomerById fonksiyonumuz da parametre olarak alınan id değerini liste içinde arıyor.Bu değerde bir veri var ise geri döndürüyor yok ise null değer döndürüyor.Bu fonksiyonun customer tipinde değer döndürdüğüne dikkat edelim. Consturctor'ın içindede
list'emize veri ekledik.Bunu tarayıcımız üzerinde GET isteği ile verinin nasıl geldiğini görmek için yaptık


package com.mycompany.api;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.util.*;
import com.mycompany.client.*;
@Path("customers")
public class CustomerWebService {
CustomerDataService dt=CustomerDataService.getInstance();
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Customer> getCustomers(){
return dt.getCustomerList();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public String createCustomer(Customer newCostumer){
return dt.addCustomer(newCostumer);
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
public Customer getCustomer(@PathParam("id") String id) {
return dt.getCustomerById(id);
}
}


Şimdide web servis sınıfımıza bakalım.Bir önceki yazımızda @Consumes ve @Produces ek açıklamalarından bahsetmiştik.Burada @GET requestin'e karşılık response döndürebilecek iki adet fonksiyon var. GET/api/customers ve GET/api/customers/0 istekler bu formatta olmalı. Bu fonksiyonların verileri JSON formatında üreteceğini görüyoruz. Diğer bir fonksiyonumuzda gelen bir post isteğini dataservisimizi kullanarak gerçekleştiriyor ve gördüğünüz üzere addCustomer metodumuz bize yeni eklenen müşterinin id'sini döndürüyor.Bu id düz yazı formatında dönüyor.Kullanıcının ise bu POST isteğinde kullanacağı verinin JSON formatında olması gerekiyor (@Consumes).Buraya kadar olan kısmı çalıştırıp GET metoduyla yapılan istekleri kontrol edelim.







package com.mycompany.client;
import javax.ws.rs.client.*;
import javax.ws.rs.core.*;
public class ClientApp {
public static void main(String []args){
Client client=ClientBuilder.newClient();
WebTarget target=client.target("http://localhost:8080/PostAnnotation/api/customers");
postUsingRawJSON(target);
postByObjectToJasonTransformation(target);
getAllCustomers(target);
}
private static void getAllCustomers(WebTarget t){
String s=t.request().get(String.class);
System.out.println("All customers : "+s);
}
private static void postUsingRawJSON(WebTarget target){
String customer = ClientUtil.createCustomerInJSON("Alyssa William"
, "1021 Hweitt Street"
, "343-343-3433");
String response = target.request()
.post(Entity.entity(customer, MediaType.APPLICATION_JSON)
, String.class);
System.out.println("customer created with id: "+response);
getCustomerById(target, response);
}
private static void getCustomerById(WebTarget target, String response) {
String s = target.path(response)
.request()
.get(String.class);
System.out.println("new customer :"+s);
}
private static void postByObjectToJasonTransformation(WebTarget target) {
Customer newCustomer = ClientUtil.
createCustomer("Jake Mae", "342, " +
"Snake Dr, GreenLake", "444-333-4564");
String response = target.request(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_PLAIN_TYPE)
.post(Entity.json(newCustomer)
,String.class);
System.out.println("customer created with id: "+response);
getCustomerById(target, response);
}
}
view raw a.java hosted with ❤ by GitHub
package com.mycompany.client;
public class ClientUtil {
public static String createCustomerInJSON(String name,String address,String phoneNumber){
return String.format("{\"name\":\"%s\",\"address\":\"%s\",\"phoneNumber\":\"%s\"}",
name, address, phoneNumber);
}
public static Customer createCustomer(String name,String address,String phoneNumber){
Customer c=new Customer();
c.setName(name);
c.setAddress(address);
c.setPhoneNumber(phoneNumber);
return c;
}
}
view raw b.java hosted with ❤ by GitHub
Bu sınıfımız clientapp sınıfımıza yardımcı bir sınıf olarak müşteri yaratmamızı sağlıyor.Bu müşteri bilgilerini JSON ve düz yazı olarak yaratan iki fonksiyonumuz mevcut.

Bu sınıfımızdaki fonksiyonlar ise oluşturduğumuz webservisine uygun formatlarda requestler yaparak dönen değerleri yazdırıyor.Buradaki mantığı anlatacak olursak siz bir request yaparken bunun isteğini belirtirsiniz.Daha sonra bu isteği yapacağınız hedef adresinizin bilinmesi ve bu adrese gidebilmeniz için bir sunucunuzun olması gerekiyor.Sunucu demişken önceki örneklerimizde glassfish'i kullanırken bu ve sonraki örneklerimizde Ertuğrul hocamın tavsiyesiyle payara'yı kullanacağız. Glassfish'ten kurtulmanın mutluluğu içerisindeyiz.Bunu kutlamamız gerekiyor :). Neyse devam edelim.Tabiki yapacağınız post isteklerinde verinin hangi formatta olduğuda önemli bunun içinde clientutil sınıfımızı yazmıştık.Önce projemizi run edip daha sonra clientapp sınıfımızı run ettiğimizi unutmayalım. Şimdi çıktılarımıza bakalım.

Umarım anlatabilmişimdir :).Herkese huzurlu günler diliyorum...






Spring Boot Uygulamasını Heroku üzerinde Deploy Etme

Bu yazımızda sizlere spring boot ile yazılmış basit bir Rest api'nin heroku üzerinde nasıl deploy edebileceğimizi göstereceğim. Önce ...