9 Mart 2015 Pazartesi

Servlet nedir?


Java ile dinamik web sayfası yapmanın bir çok yolu vardır. Bunlardan birisi servlet'tir.
Servlet, clientten gelen isteğe göre cevap döndüren bir java classıdır.
Bu cevabı client'a önceden belirlenmiş formatta bir web sayfası olarak döndürür.

Kaynaklar:
Oracle JavaEE 6 tutorial : http://docs.oracle.com/javaee/6/tutorial/doc/bnafd.html
Tomcat 7 docs: https://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/annotation/WebServlet.html

Javadoc

Javadoc'taki bilgilere göre, javax.servlet interface'i bütün servletlerin implement etmesi gereken metodları içeriyor.

public interface Servlet 
Defines methods that all servlets must implement.
A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.
To implement this interface, you can write a generic servlet that extends javax.servlet.GenericServlet or an HTTP servlet that extendsjavax.servlet.http.HttpServlet.
This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:
  1. The servlet is constructed, then initialized with the init method.
  1. Any calls from clients to the service method are handled.
  1. The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized.
In addition to the life-cycle methods, this interface provides the getServletConfig method, which the servlet can use to get any startup information, and the getServletInfo method, which allows the servlet to return basic information about itself, such as author, version, and copyright.

Bu interface'i implement eden GenericServlet sınıfı ( javax.servlet.GenericServlet ) genel amaçlı servlet sınıfıdır. Bu sınıftan kalıtım alarak örneğin bir ftp servlet de yazabiliriz.
public abstract class GenericServlet 
extends java.lang.Object
implements ServletServletConfig, java.io.Serializable

HttpServlet sınıfı işte bu GenericServlet'in alt sınıfıdır. HttpServlet ten kalıtım alındığında en azından bir metodu override etmek gerekir: genellikle doGet ya da doPost override edilir.
(Not: genellikle google seo konusundaki avantajı yüzünden doGet tercih ediliyor.)


public abstract class HttpServlet 
extends GenericServlet 
implements java.io.Serializable
Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site. A subclass of HttpServlet must override at least one method, usually one of these:
  • doGet, if the servlet supports HTTP GET requests
  • doPost, for HTTP POST requests
  • doPut, for HTTP PUT requests
  • doDelete, for HTTP DELETE requests
  • init and destroy, to manage resources that are held for the life of the servlet
  • getServletInfo, which the servlet uses to provide information about itself
There's almost no reason to override the service method. service handles standard HTTP requests by dispatching them to the handler methods for each HTTP request type (the doXXX methods listed above).
Likewise, there's almost no reason to override the doOptions and doTrace methods.
Servlets typically run on multithreaded servers, so be aware that a servlet must handle concurrent requests and be careful to synchronize access to shared resources. Shared resources include in-memory data such as instance or class variables and external objects such as files, database connections, and network connections. See the Java Tutorial on Multithreaded Programming for more information on handling multiple threads in a Java program.

HTTP servlet nasıl çalışır?


1. Client servera request gönderir.
2. Server'da bu isteğe ait servlet belirlenir. Request bu servlete gönderilir.
3. Servlet bu gelen bilgileri alır ve oluşturulması gereken sonuçları üretir. Genellikle bu sonuçlar HTML sayfası şeklindedir.
4. Servlet oluşturduğu sonucu web servera gönderir.
5. Web server servletten aldığı sonucu requestin sahibi olan client'a gönderir.

HttpServlet class'ı

HTML isteklerini anlayarak, HTML response üretir. 
HttpServlet classını extend ederek kendi servlet'lerimizi yazabiliriz.
Bunun için önce Source Packages altına yeni bir package yaratarak içerisine servlet classlarını atarız.
Daha sonra JNDI için servletleri tanımlamamız gerekir.
Bunu yapmanın 2 yolu var:
1- web.xml ile, (Servlet 3.0 dan itibaren opsiyoneldir)
2-Annotation ile. (JSR-315 (Servlet 3.0) specification ile getirildi)
İki yöntemin de artıları ve eksileri var.
Not: Hem annotation, hem de web.xml de tanımlama yapılırsa annotation xml'i ezer.

-----------
JSR-315
- pdf dosyası: http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-eval-oth-JSpec/servlet-3_0-final-spec.pdf
- JCP sayfası : https://jcp.org/en/jsr/detail?id=311
------------

1. web.xml ile servletleri tanımlamak

Bu yöntemin avantajı tek bir dosyada ekleme-çıkarma, değiştirme yapmanın kolay olmasıdır.
Ayrıca değişiklik yapıldığında serveri yeniden başlattığımız anda web.xml'in yeniden okunmasıyla değişiklikler geçerli olur.

Yapılacak işlemler:

 WEB-INF klasörü içerisine yeni bir web.xml dosyası yaratırız.

web.xml dosyası:
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
</web-app>


Buraya servletleri tanımlarız.
Örneğin: IndexServlet.java adlı servlet'i tanımlarken, Servlets tabından add servlet element seçeneğini seçeriz.
Açılan add servlet penceresinde servlet adı, sınıfı, ve URL pattern belirtiriz (posts/* gibi).

web.xml dosyasında şu eklemeler yapılır:
<servlet>
        <servlet-name>IndexServ</servlet-name>
        <servlet-class>com.example.servlets.IndexServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>IndexServ</servlet-name>
        <url-pattern>/administrator</url-pattern>
    </servlet-mapping>

Böylece localhost:8080/administrator adresine bağlandığımızda servlet'ten gelen cevabı bir html sayfa olarak görürüz.

2. Annotation ile servlet tanımlamak

Javadoc : http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/WebServlet.html

Servlet 3.0dan itibaren gelen bir yenilikle, servlet classının başına @WebServlet annotationı koyarak kolay bir şekilde tanımlama yapabiliriz.
web.xml dosyasına gitmeye gerek kalmadan, hızlı bir şekilde tanımlama işi halledilmiş olur.
Fakat burada yapılan bir değşikliğin etkisini göstermesi için bütün projenin yeniden compile edilmesi gerekir. Çünkü burada değişiklik class bazında olmaktadır.
Bu yüzden ufak bir değişiklikte bile bütün projeyi tekrardan compile etmek pek akıl karı değildir.

@WebServlet("/temppage")
public class TempServlet extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter pw = resp.getWriter();
        pw.println("<html><head></head><body>");
        pw.println("<p> query: " + req.getQueryString() + "</p>");
        pw.println("</body></html>");
    }  
}
Bir servlet annotation'ı minimum şu şekilde olmalıdır:
@WebServlet("/notification")

Name, displayName, urlPatterns, vb diğer tanımlamaları da yazacaksak şu şekilde olmalıdır:
@WebServlet( name="NotificationServlet", displayName="Notification Servlet", urlPatterns = {"/notification"}, loadOnStartup=1)

service() metodu

Gelen isteğin tipine bakarak, kendi içeriğinde bulunan bu isteğe uygun metotları çalıştırır. Bu metodların adları “do” ile başlar: doGet ( ) , doDelete ( ) , vb.
Override edilmesi mümkündür fakat gereği yoktur.

init() metodu

Servlet ilk çalıştığında yapılacak genel işlemler için kullanılır.
Örneğin; veri tabanına bağlantı kurulması gerekiyorsa, bu işlemi bir kere init ( ) metodunda oluşturup gelen bütün isteklerde o bağlantıyı kullanabiliriz.
Yazdığımız servletin yaratılırken haber vermesini istiyorsak init() metodunu override ederiz.

Örnek bir Http Servlet

Projeye sağ tıklayıp Create new -> servlet diyerek yeni servlet yaratabiliriz.


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class HelloWorld extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws IOException, ServletException
    {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>Hello World!</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Hello World!</h1>");
        out.println("</body>");
        out.println("</html>");
    }
}

web.xml dosyası

Bir java servletin browserdan erişilebilmesi için önce servlet containera bunu bildirmek gerekiyor.

Servlet containera şunların bildirilmesi gerek:
1-hangi servletleri deploy edeceği
2-bu servletlerin hangi URLlere map edileceği
Web applicationın web.xml dosyasına bunları ilave ederek servlet containerı bilgilendirmiş oluyoruz.

Yani web.xml'deki servlet tanımının ilk bölümünde servlete bir isim verip class adını belirtiyoruz.
Buradan IndexServ adlı servletin aslında com.example.servlets paketinde bulunan IndexServlet sınıfında bulunduğunu anlıyoruz.
<servlet>
        <servlet-name>IndexServ</servlet-name>
        <servlet-class>com.example.servlets.IndexServlet</servlet-class>
    </servlet>

İkinci bölümde de servlete verilen isim bir URLe map ediliyor.
IndexServ adlı servletin sadece root'ta bulunan administrator sayfasında çalıştığını anlıyoruz.
    <servlet-mapping>
        <servlet-name>IndexServ</servlet-name>
        <url-pattern>/administrator</url-pattern>
    </servlet-mapping>


HttpServletRequest ve HttpServletResponse



HTTP servlet ile gelen requestin parametrelerini kontrol edebiliyoruz. Şöyle ki:
String username = req.getParameter("username");
yazdığımızda örneğin bir formdan gelen kullanıcı adı parametresini alıp username adlı local değişkene vermiş oluruz. Daha sonra parametrelerin doğruluğunu kontrol edip ona göre bir request hazırlayabiliriz.

Bunun dışında request mesajının headerlarını da inceleyebiliriz.
//bütün headerları alır
Enumeration<String> headers = req.getHeaders();
//host headerının değerini alır
String host = req.getHeader("host");
Servlet  requestte gelen parametre vb bilgileri alıp gerekli işlemleri yaptıktan sonra duruma göre bir cevap yani response hazırlar. İşte bunu doGet metodundaki HttpServletResponse parametresini kullanarak yapıyoruz.
//response parametresi bize bir PrintWriter sağlıyor
PrintWrite pw = resp.getWriter();
//bununla yazdığımız her şey browser ekranına sanki konsola yazarmışçasına basılıyor.
pw.println("<html><body><p>Hello</p></body></html>");


...

Servlet attribute'leri



value
or
urlPatterns
String[]
Required
Specify one or more URL patterns of the servlet. Either of attribute can be used, but not both.
name
String
Optional
Name of the servlet
displayName
String
Optional
Display name of the servlet
description
String
Optional
Description of the servlet
asyncSupported
boolean
Optional
Specify whether the servlet supports asynchronous operation mode. Default is false.
initParams
WebInitParam[]
Optional
Specify one or more initialization parameters of the servlet. Each parameter is specified by@WebInitParam annotation type.
loadOnStartup
int
Optional
Specify load-on-startup order of the servlet.
smallIcon
String
Optional
Specify name of the small icon of the servlet.
largeIcon
String
Optional
Specify name of the large icon of the servlet.


Servlet annotation tipleri



Annotation type
Equivalent XML elements in web.xml
None
<http-method-exception>
<http-method>
None
<security-constraint>
<filter>, <filter-mapping>
<init-param>
<listener>
<servlet>, <servlet-mapping>

Servlet annotation örnekleri


@WebServlet(urlPatterns = {"/sendFile""/uploadFile"})



@WebServlet(
        name = "MyOwnServlet",
        description = "This is my first annotated servlet",
        urlPatterns = "/processServlet"

)


@WebServlet(
        urlPatterns = "/imageUpload",
        initParams =
        {
            @WebInitParam(name = "saveDir", value = "D:/FileUpload"),
            @WebInitParam(name = "allowedTypes", value = "jpg,jpeg,gif,png")
        }
)


@WebServlet(

        urlPatterns = "/myController",

        loadOnStartup = 1,

        asyncSupported = true

)


Http Session UML diyagramı





Hiç yorum yok:

Yorum Gönder