Servlet & JSP – 12 – Attribute
Merhaba Arkadaslar,
Bu bolumde attribute konusunu inceleyecegiz. Attribute’leri bir isme (name) sahip farkli scope’larda bulunabilen/yasayabilen objeler olarak dusunebiliriz.
Attribute icin 3 scope/yasam alani vardir ; Context , Request , Session
ServletContext –> Context
ServletRequest –> Request
HttpSession –> Session
Arabirimlerinde attribute ile ilgili su metotlar yer almaktadir.
public Object getAttribute(String name); public void setAttribute(String name, Object object); public void removeAttribute(String name); public Enumeration<String> getAttributeNames();
Context Scope
Onceki ornekte ServletContext arabirimi uzerinden setAttribute ve getAttribute metotlari kullanmistik. connectionAttribute tum uygulamamizdan ulasilabilir ve herkese aciktir.
Resmi inceledigimizde , “foo” ve “bar” adinda 2 tane context attribute var. Context attribute oldugu icin resimde oldugu gibi Client A , Client B , Client C ayni context attribute’e ulasabilir(getAttribute) ve deger atayabilir(setAttribute). Hatirlayacagimiz gibi her istek(request) bir thread olusmasini saglardi. Dolayisiyla context attribute’ler thread-safe degildir.
Peki context attribute’leri thread safe yapabilir miyiz ?
Ornegin Servlet A icin service metodunu synchronized yaparsak ? Bu durumda sadece syncronized yaptigimiz Servlet uzerinde ayni anda sadece bir thread yani bir istege cevap verilmesini saglayacaktir. Diger Servlet veya JSP’ler context attribute’lerine ulasabilir ve degistirebilir. Dolayisiyla bu durum sorunumuzu cozmeyecektir.
Context attribute’lerini korumak icin ServletContext objemizi kilitlememiz gerekir.
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter pw = resp.getWriter(); synchronized (getServletContext()) { getServletContext().setAttribute("foo", 22); getServletContext().setAttribute("bar", 42); pw.println(getServletContext().getAttribute("foo")); pw.println(getServletContext().getAttribute("bar")); } }
Context Attribute ornegini test edebilmek icin 2 tane servlet olusturacagiz.
_07_Attribute.context
ContextAttribute.java
GetContextAttribute.java
ContextAttribute.java
package _07_Attribute.context; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ContextAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext(); context.setAttribute("contextAttribute", "myContextAttribute"); // context attribute'ler tum web application icin gecerlidir. // projemizi deploy ettikten sonra bu servlet i calistiralim. // daha sonrasinda context attribute lerin tum web application icin // gecerli oldugunu gormek icin farkli bir browser dan // GetContextAttribute servletini calistiralim. // injavawetrust/getcontextattribute } }
Context attribute’ler tum web application icin gecerlidir.
Projemizi deploy ettikten sonra ContextAttribute servlet’ini calistiralim.(/contextattribute)
Daha sonrasinda context attribute lerin tum web application icin gecerli oldugunu gormek icin farkli bir browser’dan GetContextAttribute servletini calistiralim. (/getcontextattribute)
package _07_Attribute.context; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class GetContextAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = getServletContext(); String attribute = (String) context.getAttribute("contextAttribute"); System.out.println("context attribute:" + attribute); } }
web.xml dosyamiza servlet tanimlarini ekleyelim ;
<servlet> <servlet-name>ContextAttribute</servlet-name> <servlet-class>_07_Attribute.context.ContextAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>ContextAttribute</servlet-name> <url-pattern>/contextattribute</url-pattern> </servlet-mapping> <servlet> <servlet-name>GetContextAttribute</servlet-name> <servlet-class>_07_Attribute.context.GetContextAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>GetContextAttribute</servlet-name> <url-pattern>/getcontextattribute</url-pattern> </servlet-mapping>
Session Scope
Session kavramini ve HttpSession arabimini ilerleyen bolumlerde inceleyecegiz.Session, ayni client/istemciden birden fazla istek/request icin devamliligi saglar.
Session attribute‘lerini de korumak icin benzer sekilde HttpSession objesini kilitlememiz gerekir.
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter pw = resp.getWriter(); HttpSession session = req.getSession(); synchronized (session) { session.setAttribute("foo", 22); session.setAttribute("bar", 42); pw.println(session.getAttribute("foo")); pw.println(session.getAttribute("bar")); } }
Context Attribute tum web application icin gecerlidir.Session attribute , ilgili session icin gecerlidir. Bunu test edebilmek icin benzer sekilde 2 farkli browser kullanabiliriz.
_07_Attribute.session
SessionAttribute
GetSessionAttribute
package _07_Attribute.session; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class SessionAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.setAttribute("sessionAttribute", "my session attribute"); // HttpSession objesini getSession metodu ile elde edebilirz // Session attribute'ler session icinde gecerlidir. } }
package _07_Attribute.session; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class GetSessionAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); String attribute = (String) session.getAttribute("sessionAttribute"); System.out.println("session attribute : " + attribute); // test edebilmek icin farkli 2 browser kullanabiliriz. // ayni tarayicida ayni session da oldugumuz icin session attribute e // ulasabiliriz. // farkli tarayici uzerinde denedigimizde farkli session oldugu icin // null degeri donecektir. } }
web.xml dosyamiza servlet tanimlarini ekleyelim ;
<servlet> <servlet-name>SessionAttribute</servlet-name> <servlet-class>_07_Attribute.session.SessionAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>SessionAttribute</servlet-name> <url-pattern>/sessionattribute</url-pattern> </servlet-mapping> <servlet> <servlet-name>GetSessionAttribute</servlet-name> <servlet-class>_07_Attribute.session.GetSessionAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>GetSessionAttribute</servlet-name> <url-pattern>/getsessionattribute</url-pattern> </servlet-mapping>
Request Scope
Request attribute’ler ve yerel degiskenler(local variables) thread-safe’tir! Instance variables thread-safe degildir !
SingleThreadModel arabimi , servlet’in ayni anda sadece bir istek/request karsilamayi saglar. Dolayisiyla bu arabirimi uygulayan servlet sinifimizin service metodunun ayni anda calismasina engel olur. Dolayisiyla instance variable’lar da thread-safe olur.
SingleThreadModel kullanimi ya da service metodunun synchronized yapilmasi onerilen bir durum degildir ! Bunun yerine local variable uygun scope icin attribute tanimlamalari yapilmalidir.
HttpServletRequest objesine de attribute eklenebilir. Request attribute’ler sadece ilgili request icin gecerlidir.
_07_Attribute.request
RequestAttribute
GetRequestAttribute
package _07_Attribute.request; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RequestAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setAttribute("requestAttribute", "my request attribute"); // request objesine attribute ekleyebiliriz. // request attribute sadece ilgili request icin gecerlidir. } }
package _07_Attribute.request; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class GetRequestAttribute extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String attribute = (String) req.getAttribute("requestAttribute"); System.out.println("request attribute : " + attribute); // request objesine attribute eklenebilir. request attribute sadece // ilgili request'e aittir. // ayni browserda RequestAttribute(/requestattribute) calistirdiktan // sonra , GetRequestAttribute(/getrequestattribute) url'ini // calistirdigimizda null deger donecektir. } }
web.xml dosyamiza servlet tanimlarimizi ekleyelim ;
<servlet> <servlet-name>RequestAttribute</servlet-name> <servlet-class>_07_Attribute.request.RequestAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>RequestAttribute</servlet-name> <url-pattern>/requestattribute</url-pattern> </servlet-mapping> <servlet> <servlet-name>GetRequestAttribute</servlet-name> <servlet-class>_07_Attribute.request.GetRequestAttribute</servlet-class> </servlet> <servlet-mapping> <servlet-name>GetRequestAttribute</servlet-name> <url-pattern>/getrequestattribute</url-pattern> </servlet-mapping>
Request attribute kullanimi MVC yapisina uygun olarak Servlet ve JSP arasinda kullanilacaktir.MVC acilimi Model View Controller’dur. MVC bir design patterndir. Farkli dillerde her bir goreve uygun farkli component olabilir.
Servlet & JSP icin inceleyecek olursak ;
Controller gorevini Servlet ustlenecektir.
View gorevini JSP sayfalari ustlenecektir.
Model gorevini de POJO’lar ustenelecektir.
MVC, business logic gorevini servletten alir ve bu gorevi model’e yani pojolara verir. MVC design pattern’in en temel noktasi business logic ile presentation’i ayirmak ve araya bu durumu kontrol eden bir yapi koymaktir. MVC ile ilgili bir kac yazi okumaniz faydali olacaktir.
Ornek uygulamamizda Servlet (controller) , People sinifi ve JSP dosyamiz olacak. Yazilarimin basinda soyledigim gibi Servlet’lerin amaci MVC yapisinda view degil controller gorevini ustlenmektir. Uygulamamizda basit bir ArrayList olacak bu ArrayList objemizi request attribute olarak kullanacagiz, daha sonrasinda tarayiciya cikti olarak yazdirmak icin Servlet degil JSP dosyamizi kullanacagiz.
Yeni bir paket ve servlet sinifi olusturalim;
__07_Attribute.mvc.controller
RequestController.java
__07_Attribute.mvc.model
People.java
People.java
package _07_Attribute.mvc.model; public class People { Integer id; String firstName; String lastName; String gender; public People(String firstName, String lastName, String gender) { this.firstName = firstName; this.lastName = lastName; this.gender = gender; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } }
RequestController.java
package _07_Attribute.mvc.controller; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import _07_Attribute.mvc.model.People; public class RequestController extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { People person1 = new People("Levent", "Erguder", "Bay"); People person2 = new People("Semih Okan", "Pehlivan", "Bay"); People person3 = new People("Muhammet", "Cagatay", "Bay"); List peopleList = new ArrayList(); peopleList.add(person1); peopleList.add(person2); peopleList.add(person3); req.setAttribute("peopleList", peopleList); RequestDispatcher dispatcher = req .getRequestDispatcher("requestattribute/requestdispatcher.jsp"); // RequestDispatcher objemizi ServletRequest objesi uzerinden elde ettigimzide relative path kullanabiliriz. // WebContent dizini altinda requestattribute dizini olusturuldu. // requestdispatcher.jsp dosyasi bu requestattribute dizini altinda. dispatcher.forward(req, resp); } }
Onceki ornegimizde kullandigimiz People sinifimizdan 3 tane yeni obje olusturuyoruz;
People person1 = new People("Levent", "Erguder", "Bay"); People person2 = new People("Semih Okan", "Pehlivan", "Bay"); People person3 = new People("Muhammet", "Cagatay", "Bay");
ArrayList’e bu objelerimizi ekledik daha sonra request scope/yasam alanina yeni bir attribute ekliyoruz.
req.setAttribute("peopleList", peopleList);
Daha sonrasinda RequestDispatcher arabiriminin forward metodunu kullaniyoruz.
getRequestDispatcher() metodumuz ServletRequest sinifinda yer almaktadir.
public RequestDispatcher getRequestDispatcher(String path);
Burada Servletimizden , JSP dosyamiza dispatch/yonlendirme yapiyoruz. JSP dosyamizin adi requestdispatcher.jsp , bu JSP dosyamiz , WebContent klasoru icinde olusturdugumuz requestattribute klasorunde yer almaktadir. Bu nedenle bu klasorun de adini verdik.
RequestDispatcher view = req.getRequestDispatcher("requestattribute/requestdispatcher.jsp"); view.forward(req, resp);
web.xml dosyamizda servlet tanimimiz;
<servlet> <servlet-name>RequestController</servlet-name> <servlet-class>_07_Attribute.mvc.controller.RequestController</servlet-class> </servlet> <servlet-mapping> <servlet-name>RequestController</servlet-name> <url-pattern>/requestcontroller</url-pattern> </servlet-mapping>
requestdispatcher.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <%@page import="java.util.List"%> <%@page import="_07_Attribute.mvc.model.People"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>RequestDispatcher</title> </head> <body> <h1>RequestDispatcher</h1> <% List<People> pList = (List<People>) request.getAttribute("peopleList"); %> <table style="width: 300px"> <% for (People person : pList) { %> <tr> <td><%=person.getGender()%></td> <td><%=person.getFirstName()%></td> <td><%=person.getLastName()%></td> </tr> <% } %> </table> </body> </html>
Servletimizi calistiralim ;
Servlet dosyamizi calistirdigimizda uygulamamiz JSP dosyamiza yonlendirilecektir ve JSP dosyamiz calisacaktir. Burada URL degismeyecektir !
forward metodu sendRedirect metodundan farklidir.
- forward metodunda url degismez , sendRedirect metodunda url degisir.
- Dispatch islemi server’da olur , Redirect islemi ise client’ta olur.
- Redirect islemini soyle dusunebiliriz ; musteri bir problemle karsilasti ve sizi aradi siz bu isten ben sorumlu degilim diyerek musteriyi farkli bir kisiye yonlendiriyorsunuz. (url degisir)
- Dispatch islemi ise ; musterinin karsilastigi problemi cozerken calisma arkadasinizdan yardim aliyorsunuz arka planda isin sizin yaptiginiz sanilirken aslinda calisma arkadasiniz bu isi yapmaktadir. Musterinin bundan haberi yoktur.( url degismez)
Bu ornegimizde oldugu gibi RequestDispatcher objemizi ServletRequest arabirimi uzerinden alirsak , getRequestDispatcher metoduna verdigimiz String arguman relative path olacaktir. relative path “/” ile baslamaz.
RequestDispatcher view = req.getRequestDispatcher("requestattribute/requestdispatcher.jsp");
RequestDispatcher objemizi ServletContext arabirimi uzerinden alirsak , URL de absolute path bilgisi vermemiz gerekir. Dolayisilar “/” ile baslamak zorundadir.
Servlet sinifimizda RequestDispatcher objemizi ServletContext uzerinden alirsak ve relative path kullanirsak su hatayi aliriz;
HTTP Status 500 – Path requestattribute/requestdispatcher.jsp does not start with a “/” character
RequestController2.java
package _07_Attribute.mvc.controller; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import _07_Attribute.mvc.model.People; public class RequestController2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { People person1 = new People("Levent", "Erguder", "Bay"); People person2 = new People("Semih Okan", "Pehlivan", "Bay"); People person3 = new People("Muhammet", "Cagatay", "Bay"); List peopleList = new ArrayList(); peopleList.add(person1); peopleList.add(person2); peopleList.add(person3); req.setAttribute("peopleList", peopleList); ServletContext context = getServletContext(); // RequestDispatcher dispatcher = context // .getRequestDispatcher("requestattribute/requestdispatcher.jsp"); // #### / ile baslamalidir! RequestDispatcher dispatcher = context .getRequestDispatcher("/requestattribute/requestdispatcher.jsp"); // RequestDispatcher objesi ServletContext (context) uzerinden elde // ediliyorsa bu durumda absolute path kullanilmalidir. // Yani / ile baslamalidir! dispatcher.forward(req, resp); } }
web.xml dosyamiza servlet taninini ekleyelim;
<servlet> <servlet-name>RequestController2</servlet-name> <servlet-class>_07_Attribute.mvc.controller.RequestController2</servlet-class> </servlet> <servlet-mapping> <servlet-name>RequestController2</servlet-name> <url-pattern>/requestcontroller2</url-pattern> </servlet-mapping>
Son olarak, eger forwad metodunu cagirmadan once getOutputStream metodunu cagirirsak
IllegalStateException hatasi aliriz ;
resp.getOutputStream(); // #### forward metodundan once getOutputStream metodu cagrilirsa // java.lang.IllegalStateException: getOutputStream() has already been // called for this response hatasi alinir
HTTP Status 500 – java.lang.IllegalStateException: getOutputStream() has already been called for this response
Yazimi burada sonlandiriyorum.
Herkese Bol Javali Gunler dilerim.
Be an oracle man , import java.*;
Levent Erguder
OCP, Java SE 6 Programmer
OCE, Java EE 6 Web Component Developer
Leave a Reply