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.- The servlet is constructed, then initialized with the
init
method. - Any calls from clients to the
service
method are handled. - The servlet is taken out of service, then destroyed with the
destroy
method, then garbage collected and finalized.
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 extendsjavax.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:
In addition to the life-cycle methods, this interface provides the
getServletConfig
method, which the servlet can use to get any startup information, and thegetServletInfo
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 Servlet, ServletConfig, 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.)
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.
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 ofHttpServlet
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
anddestroy
, to manage resources that are held for the life of the servletThere's almost no reason to override the
getServletInfo
, which the servlet uses to provide information about itselfservice
method.service
handles standard HTTP requests by dispatching them to the handler methods for each HTTP request type (thedo
XXX methods listed above).
Likewise, there's almost no reason to override thedoOptions
anddoTrace
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
------------
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.
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("/notification")
Name, displayName, urlPatterns, vb diğer tanımlamaları da yazacaksak şu şekilde olmalıdır:
Override edilmesi mümkündür fakat gereği yoktur.
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.
İ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.
HTTP servlet ile gelen requestin parametrelerini kontrol edebiliyoruz. Şöyle ki:
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.htmlServlet 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.
Bir servlet annotation'ı minimum şu şekilde olmalıdır:
@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>");
}
}
@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.
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
)
Hiç yorum yok:
Yorum Gönder