forked from burakbayramli/books
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapweb.tex
3028 lines (2584 loc) · 125 KB
/
chapweb.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\movetooddpage
\chapter{Web Uygulamaları} \label{web}
\thischapterhas{
\item Bir Web projesinin geliştirme ve hedef ortamını kurmak için gerekenler
\item Türkçe karakter desteği ve ulusallaştırma
\item Struts ve JSTL Etiketleri
\item Genel Web ihtiyaçlari ve çözümleri
}
\versal{A}\textsc{ynı} anda birçok kullanıcıya hizmet verebilen servis tarafı
Web teknolojileri, ve dinamik içerik göstermek için kullanılan Web sayfası
etiket dilleri şu anki hâline gelmek için uzun bir evrimden geçti. Dinamik
içerik, ilk nesilde, Perl, sh, bash, C gibi dillerle yazılmış, Apache Web Server
tarafından işler kod olarak çağırılan CGI programları tarafından üretiliyordu.
Java dünyası, CGI yerine pür Java Uygulama Servisleri tarafından çağırılabilen
Java Servlet'leri yerleştirdi, ve içerik göstermek için de JSP adlı etiket
dilini bize sundu. Bu ilk nesilde, görsel {\em olmayan} işlemleri dahi Servlet
yerine görsel amaçlı yazılmış JSP'lerden yapmak mümkün oluyordu, ki bu tür
kullanıma Model I ismi de verilmiştir. Fakat Model I, aksiyon JSP'leri ile
içerik JSP'lerini birbirinden ayırmayarak bakımı zor mimarilere sebebiyet
verdiği için, bir süre sonra Model II'ye geçilmiştir.
Model II, aksiyonlar (veri tabanından bilgi almak, hata kontrolü gibi işlemler)
için ayrı JSP'ler yazılmasını öngörüyordu. Fakat bu mimariden de hâlen eksik
olan faktör, meselâ bir HTML form'undan bilgi almak, kullanıcının tarayıcısını
başarı ya da hata sonrası bir sayfaya gönderebilmek gibi işlemler için
sağlanması gereken altyapı hizmetleri idi, ve bu işlemler JSP (ya da Servlet)
içinden Java kodu yazılarak programcıya zahmet getiren bir şekilde yapılması
gerekiyordu.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
\section{MVC}
Bunun üzerine daha önce masaüstü görsel programlar için başarıyla kullanılmış
MVC mimari şekli Web dünyasına uyarlanmaya başlandı. MVC mimarileri ve ürünleri,
görsel bir programı üç ana bölüme ayırıp her bölüme ayrı altyapı kodları ve
hizmetleri sağlayarak bakımı kolay kodlar yazmamıza yardım eden
mimarilerdir. MVC programının ana bölümleri şunlardır:
\begin{itemize}
\item Model
\item View
\item Controller
\end{itemize}
\textbf{Model}, hakkında program yazdığımız iş alanını hakkındaki kuralları,
hesapları yaptırdığımız alan modelini temsil eden nesnelerdir. Meselâ kurumsal
programınızı yazdığınız şirket (müşteriniz) araba kiralama hizmeti veren bir
şirket olsaydı, bu program içinde \PVerb!Car! nesnesi, {\em modelin} parçası
olurdu.
\textbf{View}, görsel işlevleri yerine getiren kodlardır. Ekrana bilgi göstermek
için yapılan tüm çağrıların toplamı MVC'nin V'sini (View) oluşturacaktır.
\textbf{Controller}, yâni kontrolcu, görsel programınızın akışını, hangi sayfadan sonra
hangi sayfaya, hatalardan sonra hangi görsel birime yönlendirileceğini kontrol
eden kısımdır. Bu birime yönlendirici, ya da trafik polisi ismi de
verilebilirdi.
Java dünyasında MVC mimarisini destekleyen birçok ürün mecuttur. Bu ürünlerden
en tanınmışı ve stabil hâlde olanı, Apache projesi tarafından sunulan Struts
projesidir.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
\section{Ana Kavramlar}
Görsel Web mimarilerinde çok sık lazım olan kalıplar, Apache Struts tarafından
MVC altyapısı çerçevesine koyularak, Jakarta Struts projesi oluşturuldu. Modern
Web uygulamalarında çok ihtiyaç duyulan kodlama gereklilikleri şunlardı:
\begin{itemize}
\item Giriş yapılan Web sayfalarından, yani Form'lardan, veri alıp vermeyi
rahatlaştırmak.
\item JSP'de bir düğme (button) basış hareketine tekabül eden bir `işlemi',
tekrar kullanılır (reusable) bir nesne içinde muhafaza etmek, ve bir Web
uygulamasını artık bu işlemlerin (action) biraraya konulduğu bir bütün olarak
görmek.
\item Sayfalar arası akış tanımlarını (flow) Servlet'lerin, yani Java kodunun,
içinden kurtarıp bir ayar dosyası içinde tutmak, böylece akışı değiştirmeyi
kolaylaştırmak. Ayrıca bu sayede akış içindeki işlemleri de daha rahat tekrar
kullanılır hale getirmek.
\end{itemize}
\subsection{Form ve Action} \label{web:requirements}
\begin{figure}[!hbp]
\center{
\scalebox{0.60}{
\includegraphics{./images/struts_request_response_action.eps}
}
}
\caption{Request, Response ve Struts Action}
\end{figure}
Bir Struts projesi \PVerb!struts-config.xml! denen ayar dosyası etrafında
döner. Bu dosya, şu şekilde tanımlar içerir.
\begin{lstlisting}[language=XML, frame=none]
<form-beans>
<form-bean
name="AddCarForm"
type="org.apache.struts.action.DynaActionForm">
<form-property
name="licensePlate"
type="java.lang.String"
initial=""/>
<form-property
name="description"
type="java.lang.String"
initial=""/>
</form-bean>
</form-beans>
<action-mappings>
<action
path="/main"
scope="session"
type="org.mycompany.kitapdemo.actions.GetCarsAction">
<forward name="fail" path="/pages/main.jsp"/>
<forward name="success" path="/pages/main.jsp"/>
</action>
<action
path="/add-car"
scope="session"
type="org.mycompany.kitapdemo.actions.AddCarAction"
name="AddCarForm"
validate="false">
<forward name="success" path="/main.do"/>
<forward name="fail" path="/main.do"/>
</action>
</action-mappings>
\end{lstlisting}
İki tanım herhalde hemen gözünüze çarpmıştır. Biri \PVerb!AddCarForm!, öteki
\PVerb!AddCarAction!. Struts kodu yazarken, ya bir JSP, ya bir Form, ya da bir
Action yazıyoruzdur. Form, tahmin edileceği gibi veri girilen bir Form
sayfasının üzerindeki değerleri tutan bir Java Bean nesnesidir. Üzerinde sadece
get, set, reset, ya da validate gibi metotlar vardır. Struts'ın sağladığı önemli
bir rahatlık, özel etiketler üzerinden sayfanızdaki alanları bu Bean'e otomatik
olarak bağlamak olacaktır. Sayfadaki alan değişince bu bean'deki eşlenmiş olan
değer de değişecektir. Böylece Java sunucu tarafındaki kodlarınız get/set
kullanarak sayfa verilerine erişebilmiş olur. Hattâ en son Struts
versiyonlarında, üzerinde get/set metotları olan ayrı bir bean'e bile
ihtiyacımız kalmamıstır; Artık bu bean Struts \PVerb!DynaActionForm! kullanımı
sayesinde dinamik olarak üretilebilmektedir.
Action (işlem) ise, bir düğmeye bastığımızda yapılması gereken işlemi
kodladığımız yerdir. O da bir Java nesnesidir, ve JSP sayfası içinde
(\PVerb!struts-config.xml!'de tanımlanan ismi üzerinden) cağırılması gerekir.
``Çağırılması'' kelimesi tabii Struts için tam uygun bir kelime
değildir. Sayfadaki düğmeler ile Action'lar, \PVerb!struts-config.xml! içinde
``eşlenir'' demek daha uygun olur. Çünkü çâğırma işleminin kendisini
Struts mimarisi kapalı kapılar arkasında yapmaktadır.
JSP sayfasında bir düğme ile Action'ı eşlemek şöyle olur.
\begin{lstlisting}[language=XML, frame=none]
<html:form action="/add-car.do">
...
<td>
<html:submit>Araba Ekle</html:submit>
</td>
</html:form>
\end{lstlisting}
\PVerb!add-car.do! bağlantısı ise, sonunda \PVerb!.do! kelimesi içerdiği için
bir Struts Action bağlantısıdır. Struts projenizi kurduğunuzda Web Sunucunuza
(Tomcat, Weblogic, JBoss) verdiğiniz \PVerb!web.xml! içerisinde, \PVerb!.do!
adlı soneki, Struts ana işlemci Servlet'ine bağlanması gerektiğini Web
Sunucusuna belirtmemiz gerekmektedir. Proje bazında tüm Action'lar için bir kere
yapılması yeterli olan bu tanımı merak edenler, örnek uygulamamızda
\PVerb!web.xml! içine bakabilirler; Aşağıdaki türden bir ibare göreceklerdir.
\begin{lstlisting}[language=XML, frame=none]
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
...
</servlet>
\end{lstlisting}
\subsection{JSP ve Form Bağlantıları}
Struts altyapısı, Form'lara otomatik değer aktarabilmek (ve daha başka görsel
amaçlar için de) özel Struts etiketleri sağlar. Yâni bir Struts projesinde JSP
yazarken bildiğimiz \PVerb!jsp:bean! türünden etiketler değil, Struts
\PVerb!html:text! gibi etiketler kullanacağız. Meselâ, sayfamıza bir metin
(text) alanı koyup, bu alanı, Form bean'i üzerindeki bir alana bağlamak istesek,
\begin{lstlisting}[language=XML, frame=none]
<html:text property=``licensePlate''/>
\end{lstlisting}
gibi bir ifade kullanmamız gerekir. \PVerb!licensePlate! (plaka) adı ile
belirtilen bu metin giriş alanı ekteki örnek kodlarda \PVerb!AddCarForm!
nesnesi üzerindeki \PVerb!getLicensePlate!, \PVerb!setLicensePlate! metotlarına
eşlenecektir. Yani, Struts altyapısı tarafında çağırılacaktır. (Tabii
\PVerb!DynaActionForm! kullanımı var ise, get/set içeren bean'in varlığına bile
gerek yoktur, dinamik \PVerb!AddCarForm! nesnesinin get/set metotları dinamik
olarak çağırılacaktır).
Dikkat edelim, get ve set'in ``ikisinin birden'' Struts tarafından
çağrılacağından / kullanılacağından bahsettim. Struts, Form bean'ine sadece tek
bir zamanda değer aktarmaz. Değer aktarımı ters yön içinde geçerlidir, yani,
arka planda Java üzerinden Form'da değişiklik yapıp bir sayfaya tekrar
döndügünüzde, sayfadaki değerin de değiştiğini göreceksiniz.
ComboBox, Radio Button gibi görsel birimlerin ayrı ayrı \PVerb!html:! kullanımı
vardır.
\subsection{Action'lardan Sonra Yönlendirme} \label{web:struts:action}
Struts'ın üstlendiği önemli diğer bir görevde, uygulamanız için trafik polisliği
görevidir. Normal Java web uygulamalarında bir Servlet'ten öteki Servlet'e aktarım
\PVerb!redirect! çağrısı ile yapıyorduk. Fakat bu yöntem sonraki sayfa
ismini direk JSP içine gömmesi sebebiyle kod muhafazası ve bakımı açısından
iyi bir yöntem değildir.
Struts mimarisi, yönlendirme tanımlarını Java kodu içerisinden çıkartarak bir
ayar dosyasına koyarak değiştirilmesini rahatlatmış, ve bu şekilde Java
kodlarının daha temiz ve modüler olmasını sağlamıştır.
Mesela örnek uygulamamızda \PVerb!AddCarAction! işlendikten sonra diğer bir
Action olan \PVerb!get-cars.do!'ya gitmek istesek, bunun için Java kodu
yazmamıza gerek yoktur. \PVerb!struts-config.xml! içinde, \PVerb!AddCarAction!
tanımı altında, bu yönü belirtmemiz yeterlidir. Struts Action class'ı sadece ve
sadece bir durum kodu döndürmekle yükümlüdür. Bu durum koduna bağlı olarak
nereye gidileceğinin kararını \PVerb!struts-config.xml! dosyası
verecektir. Örnek Action tanımımızdaki
\begin{lstlisting}[language=XML, frame=none]
<action
path="/add-car"
..
<forward name="success" path="/main.do"/>
<forward name="fail" path="/main.do"/>
\end{lstlisting}
kullanımı, \PVerb!success! durum kodu döndürüldüğünde \PVerb!/main.do!, hata
döndürüldüğünde de yine \PVerb!/main.do!'ya gidilmesini belirtmiştir (durum kodu
\PVerb!fail! için gidilecek yer değişik bir yer de olabilirdi. Bu tanım
programcıya ait bir seçimdir. Genellikle ekleme ekranlarındaki hataları aynı
sayfada gösterek iyi olduğu için bu yöntem seçilmiştir). \PVerb!main.do!'nun
kendisi de nihai olarak bir JSP sayfasını gösterecektir, böylece Controller
(Action) aşamasından sonra View aşamasına geldiğimizi görüyoruz.
\begin{lstlisting}[language=Java, frame=none]
<action
path="/main"
scope="session"
..
<forward name="fail" path="/pages/main.jsp"/>
<forward name="success" path="/pages/main.jsp"/>
</action>
\end{lstlisting}
\subsection{Action Zincirleme}
Struts teknolojisinin Action ve yönlendirme yeteneği sayesinde kullanıcının
tıklaması ve bir View içeren (sayfa) gelmesi arasında birkaç tane Action'ın
zincirleme bir şekilde işletilmesi bile mümkündür. Modüler tasarım açısından
bunu yapmak faydalı da olabilir. Struts projelerinizde filanca aksiyona ihtiyaç
duyup ta ``ah böyle bir Action zâten başka bir tarafından yazılmış, onu
kullanayım'' diyerek o mevcut Action'ı zincire kattığımız çok olmuştur. Bu,
Struts'ın MVC modüler altyapısı sayesinde tekrar kullanılabilir Action'ların
yazılabilmesi sayesinde olmuştur. Yeni bir Action'ı zincire katmak, Java
kodlaması gerektirmediği için, \PVerb!struts-config.xml! seviyesinde yapılan
değişiklikler yeterli olacaktır.
Meselâ, elimizde \PVerb!GetGaragesList! adında tüm garajların listesini alıp web
oturumu üzerinde \PVerb!garageList! değişkeniyle depolayan bir Action olsun. Bu
action, normâlde \PVerb!garage-list.do! adında garajları listeleyen bir sayfa
\PVerb!garages.jsp! için kullanılmaktadır. \PVerb!struts-config.xml! şöyledir.
\begin{lstlisting}[language=Java, frame=none]
<action
path="/garage-list"
scope="session"
type="org.mycompany.kitapdemo.actions.GetGaragesAction"
validate="false">
<forward name="success" path="/pages/garages.jsp"/>
<forward name="fail" path="/pages/garages.jsp"/>
</action>
\end{lstlisting}
Fakat diyelim ki, yeni bir sayfa yazıyoruz. Bu \PVerb!newPage.jsp! adında yeni
sayfa için gösterilen bir takım diğer şeylere ek olarak, bir de garaj listesini
bir seçim listesi (listbox) içinde göstermek gerekiyor. Garaj listesini nereden
alacağız? Yeni Action içinde bir daha garaj sorgulaması yapmak bir çözüm
olabilir, fakat buna gerek yok. Daha önce yazdığımız \PVerb!GetGaragesAction!'ı
kullanabiliriz ve yeni Action'ımıza zincirleyebiliriz.
\begin{lstlisting}[language=Java, frame=none]
<action
path="/new-action"
scope="session"
type="org.mycompany.kitapdemo.actions.NewActionX">
<forward name="success" path="garage-list-for-x"/>
<forward name="fail" path="/pages/error.jsp"/>
</action>
<action
path="/garage-list-for-x"
scope="session"
type="org.mycompany.kitapdemo.actions.GetGaragesAction"
validate="false">
<forward name="success" path="/pages/newPage.jsp"/>
<forward name="fail" path="/pages/newPage.jsp"/>
</action>
\end{lstlisting}
\subsection{Struts ve JSTL}
Apache Struts, mimari açıdan MVC'nin hem Controller, hem View tarafını
gerçekleştiren bir pakettir. Controller, çünkü Struts'ın önemli bir hizmeti,
aksiyon birimlerine ve yönlendirme işlemlerine bir altyapı sağlamasıdır. View, çünkü
Form nesneleri ve JSP arasında kurulmuş ilintiler sayesinde View tarafı için de
verilen hizmetler vardır.
Tek eksik, Struts'ın etiketlerinin çok çetrefilli sunum stilleri bazen yetersiz
kalmasıdır. Mesela, bir URL'i \PVerb!html:link! ile dinamik olarak oluştururken,
{\em birden fazla} URL parametresi kullanamamaktayız.
Bu ve diğer bazı etkenler yüzünden, pür prezentasyon ihtiyaçları için
kitabımızda Struts'ın Controller ve Form hizmetlerinin üstüne, pür prezentasyon
amaçlı olarak JSTL adlı etiket dilini kullanmayı seçtik. JSTL, JSP Standart
Etiket Kütüphanesi (JSP Standart Tag Library) kelimesinin kısaltılmışıdır. JSTL,
eski JSP dilinden çok daha güçlü bir dil olarak yeni nesil etiket dillerine
standart getirmeyi amaçlamıştır. Java dünyasından standartların her zaman
başarılı olduğu söylenemez, fakat JSTL için ayrıca bir referans gerçekleştirimi
(reference implementation) sağlandığı için ortada bir işler kod vardır, ve
etiket dilinin temizliği tüm bunlara eklenince ortaya Java Web dünyası için
tercih edilir bir seçenek çıkmıştır.
Bu sebeple, kitabımızdaki tüm örneklerde, ve tavsiye ettiğimiz mimari ve ürünsel
yelpazede JSTL'i bulacaksınız.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
\section[Geliştirme Ortamı][GELİŞTİRME ORTAMI]{Geliştirme Ortamı}\label{web:development}
Kitabımızdaki örnek Web kodlarını işletmek için JBoss Uygulama Servisi'ni
kullanacağız. JBoss'ta bir web uygulamasını işleme koymak için,
\PVerb!JBOSS/default/deploy! dizini altına sonuç kodlarını göndermek
gerekir. Fakat bu, \PVerb!.class! dosyalarını olduğu gibi \PVerb!deploy! dizini
altına kopyalayabiliriz demek değildir. J2EE standartının mecbur kıldığı özel
bir paketleme sistemini takip etmemiz gerekiyor. Bu paketleme çeşitleri
şunlardır: EAR, SAR ve WAR.
En üst seviye paket EAR paketidir. EAR'in içine SAR, SAR'ın içine de WAR
konur. Eğer uygulamanızda EJB bileşeni yok ise, sadece EAR ile uğraşmadan direk
SAR kullanabilirsiniz. Biz, Struts odaklı tüm örnek uygulamalarımızda SAR
paketlemesini kullanacağız.
Önemli bir husus, açık paket vs. kapalı paketleme konusudur. SAR, EAR ve WAR,
aynen JAR yönteminde olduğu gibi sıkıştırılmış bir zip dosyası olabilirler. Biz
bu yöntem yerine, sıkıştırılacak dosyaların açık bir şekilde tutulmasını
seçtik. JBoss Uygulama Servisi, 3. versiyonundan itibaren, \PVerb!deploy!
altında gördüğü \PVerb!proje.sar! dosyası ile \PVerb!proje.sar! {\em dizinini}
eşdeğer tutmaktadır. Yâni, bir SAR içine zipleyerek koyacağınız dosyaları bir
SAR dizini altına kopyalarsanız, JBoss servisi uygulamanızı fark gözetmeden
işleme koyacaktır.
Niye açık dizin yapısını seçtik? Çünkü sonuç (production) makinasına kod
gönderirken bazı ayar dosyalarının o makina için değişmesi gerekiyor. Eğer
kapalı bir SAR, EAR, WAR dosyası gönderiyor olsaydık, bu dosyaların {\em içinde}
kalmış olan ayar dosyalarını sonradan değiştirmemiz mümkün olmazdı. Tabii ki her
makina için {\em özel} EAR, SAR, WAR {\em derlemek} mümkündür, fakat sonuç
ortamı için değişik derleme yapmak kesinlikle idare edilebilir bir yöntem
değildir. Öncelikle her makina için değişik olacak ayar dosyalarının derleme
sistemine bildirilmesi gerekmektedir. Bu derleme sistemini daha
karıştıracaktır.
Bu sebeple her makina için gerekli ayar dosyalarını derleme ve kod gönderimden
{\em sonra} EAR, SAR, WAR {\em içinde} değiştirmek (eskisinin üzerine yazmak),
daha idare edilebilir bir yöntem olmuştur. En önemlisi, bu yöntemi takip ederek
sistem admin'lerine ayar dosyalarını {\em elle bile} değiştirme seçeneğini
sağlamış oluyoruz.
Şimdi, veri tabanına erişen kurumsal bir Struts uygulamasını geliştirmek için
gereken \textbf{geliştirme} ve \textbf{hedef} dizin yapılarını görelim. Hedef
Uygulama Servisimiz JBoss 4.0.1, ve hedef dizinleri JBoss'un kuruluş dizinin
altında alttaki gibi olacaktır.
\subsection{Geliştirme Dizinleri} \label{web:devtree}
\begin{lstlisting}[language=XML, frame=none]
+- StrutsHibSimple
| +- build.properties
| +- build.xml
| | +- dd
| | | +- jboss-service.xml
| | | +- struts-config.xml
| | | +- tiles-defs.xml
| | | +- validation.xml
| | | +- validator-rules.xml
| | | +- web.xml
| | | +- META-INF
| | | | +- MANIFEST.MF
| | | +- tags
| | | | +- c-rt.tld
| | | | +- c.tld
| | | | +- fmt-rt.tld
| | | | +- fmt.tld
| | | | +- sql-rt.tld
| | | | +- sql.tld
| | | | +- struts-bean.tld
| | | | +- struts-html.tld
| | | | +- struts-logic.tld
| | | | +- struts-nested.tld
| | | | +- struts-tiles.tld
| | | | +- x-rt.tld
| | | | +- x.tld
| | +- lib
| | | +- c3p0-0.8.4.5.jar
| | | ...
| | | ...
| | | +- cglib-full-2.0.2.jar
| | | +- commons-beanutils.jar
| | | +- hibernate3.jar
| | | +- xml-apis.jar
| | +- resources
| | | +- application.properties
| | | +- hibernate.cfg.xml
| | | +- log4j.properties
| | | +- log4j.xml
| | | +- oscache.properties
| | +- src
| | | +- java
| | | |+- org
| | | | +- mycompany
| | | | | +- kitapdemo
| | | | | | +- actions
| | | | | | | +- AddCarAction.java
| | | | | | | +- GetCarsAction.java
| | | | | +- dao
| | | | | | +- Dao.java
| | | | | +- pojo
| | | | | | +- Car.hbm.xml
| | | | | | +- Car.java
| | | | | +- service
| | | | | | +- AppStartup.java
| | | | | | +- AppStartupMBean.java
| | | | | | +- HibernateSession.java
| | | | | +- util
| | | | | | +- AllTest.java
| | | | | | +- ClassPathFile.java
| | | | | | +- RequestCharacterEncodingFilter.java
| | | | | | +- TestUtil.java
| | | +- pages
| | | | +- detail.jsp
| | | | +- main.jsp
| | | +- sql
| | | | +- tables_mysql.sql
\end{lstlisting}
Bu geliştirme dizin yapısında aranan dosyayı bulmak oldukça rahattır. En üst
seviyede \PVerb!src/!, \PVerb!resources/!, \PVerb!dd/! ve \PVerb!lib/!
dizinleri konulmuştur. Eğer yeni bir JBoss tanım XML'i konmak istense, bunun
\PVerb!dd/! altına gideceği bellidir. Aynı şekilde uygulamanın kendi içinde
kullandığı ayarlar için properties ayar dosyaları ve diğer XML bazlı dosyalar
\PVerb!resources/! altında gene en üst seviyeden erişilir hâldedir. Kaynak
dosya kategorisine giren her şey, \PVerb!src/! altındadır: JSP sayfaları, Java
kodları ve SQL DDL komutları gibi kalemler bu dizin altında alt dizinler olarak
bulunacaktır.
\subsection{Hedef Dizinleri} \label{web:deploytree}
Geliştirme dizininize gidip, komut satırından \PVerb!ant! komutunu
işlettiğinizde, \PVerb!JBOSS/server/default/deploy! altında aşağıdaki dizin
yapısının oluştuğunu göreceksiniz.
\begin{lstlisting}[language=XML, frame=none]
+- kitapdemo.sar
| +- META-INF
| | | +- jboss-service.xml
| | +- conf
| | | +- log4j.xml
| | +- kitapdemo.war
| | | +- pages
| | | | +- detail.jsp
| | | | +- main.jsp
| | | +- META-INF
| | | | +- MANIFEST.MF
| | | +- WEB-INF
| | | | +- jboss-service.xml
| | | | +- struts-config.xml
| | | | +- tiles-defs.xml
| | | | +- validation.xml
| | | | +- validator-rules.xml
| | | | +- web.xml
| | | | +- classes
| | | | | +- application.properties
| | | | | +- hibernate.cfg.xml
| | | | | +- log4j.properties
| | | | | +- log4j.xml
| | | | | +- oscache.properties
| | | | | +- org
| | | | | | +- mycompany
| | | | | | | +- kitapdemo
| | | | | | | | +- actions
| | | | | | | | | +- AddCarAction.class
| | | | | | | | | +- GetCarsAction.class
| | | | | | | | +- dao
| | | | | | | | | +- Dao.class
| | | | | | | | +- pojo
| | | | | | | | | +- Car.hbm.xml
| | | | | | | | | +- Car.class
| | | | | | | | +- service
| | | | | | | | | +- AppStartup.class
| | | | | | | | | +- AppStartupMBean.class
| | | | | | | | | +- HibernateSession.class
| | | | | | | | +- util
| | | | | | | | | +- AllTest.class
| | | | | | | | | +- ClassPathFile.class
| | | | | | | | | +- RequestCharacterEncodingFilter.class
| | | | | | | | | +- TestUtil.class
| | | | +- lib
| | | | | +- activation.jar
| | | | | +- ant-antlr-1.6.2.jar
| | | | | +- antlr-2.7.4.jar
| | | | | +- c3p0-0.8.4.5.jar
| | | | | +- cglib-full-2.0.2.jar
| | | | | +- commons-beanutils.jar
| | | | | +- commons-codec-1.3.jar
| | | | | ...
| | | | | ...
| | | | | +- standard.jar
| | | | | +- struts.jar
| | | | | +- xalan.jar
| | | | | +- xml-apis.jar
| | | | +- tags
| | | | | +- c.tld
| | | | | +- c-rt.tld
| | | | | +- struts-html.tld
\end{lstlisting}
Bu yapı JBoss tarafından işleme konmaya hazırdır. Yapı olarak, görüldüğü gibi
WAR dizini, SAR dizini içine konmuştur.
\subsection{Web Ayar Dosyaları}
Bir SAR paketi içine konulan ayar dosyalarını teker teker tanıyalım.
\subsubsection{jboss-service.xml} \label{web:config:jbosservice}
Bir SAR paketi JBoss tarafından yüklenirken o proje için yapılması gereken
hazırlıklar, \PVerb!jboss-service.xml! dosyasında belirlenir. JBoss bu dosyayı
her zaman SAR paketinin \PVerb!META-INF! dizini altında arayacaktır.
Bu dosyada, başlatılmasını istediğimiz MBean class'larını belirtmemiz gerekir
(MBean'leri daha yakından JMX ile ilgili \ref{deploymonitor:jmx}. bölümde tanıyacağız). Bir
MBean, standart bir arayüzü (interface) gerçekleştiren (implement) bir Java
class'ıdır. Kendi yazdığımız kod olabileceği gibi JBoss, ya da diğer açık
yazılım paketlerinden gelen bir MBean class'ı da olabilir.
\PVerb!StrutsHibSimple! örneğinde, Log4J paketinin baslangıç işlerinin yapan
MBean nesnesinin, ve demo'muzun kendi başlangıç kodlarının olduğu
\PVerb!AppStartup! adlı MBean'in başlatılmasını istedik. Bunları yapmak için
gereken \PVerb!jboss-service.xml! şöyle olacaktır.
\begin{lstlisting}[language=XML, caption=jboss-service.xml]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server>
<server>
<!-- AppStartup adlı class başlangıç kodlarımızı taşıyor. -->
<mbean code="org.mycompany.kitapdemo.service.AppStartup"
name=":service=AppStartup"/>
<!-- Log4J -->
<mbean code="org.jboss.logging.Log4jService"
name="jboss.system:type=KitapDemoLog4jService,
service=KitapLogging">
<!-- Ayar dosyasının yeri ve ismi. -->
<attribute name="ConfigurationURL">resource:conf/log4j.xml
</attribute>
<attribute name="Log4jQuietMode">true</attribute>
<!-- Ayar dosyasının ne kadar sıklıkla kontrol edileceği -->
<attribute name="RefreshPeriod">60</attribute>
</mbean>
</server>
\end{lstlisting}
\subsubsection{log4j.xml} \label{web:install:log4j}
\PVerb!Log4j.xml!, Log4J loglama sisteminin ayarlarını yapmak için
kullanılır. Aslında, bu ayar dosya ismi isteğe göre değişebilir; Hangi ismin
kullanılacağını \PVerb!jboss-service.xml! içinde \PVerb!resource:<dosya yeri,
ismi>! üzerinden belirtmek gerekmektedir. Dosya yeri ve ismi,
\PVerb!kitapdemo.sar! referans alınarak aranacaktır. Örneğimizde
\PVerb!jboss-service.xml! içinde \PVerb!conf/log4j.xml! ayarı kullanıldığı
için, \PVerb!kitapdemo.sar/conf/log4.xml! adlı bir dosya aranacaktır. Ayar
dosyası \PVerb!log4j.xml! içinde, hangi Java paketlerinin loglama yapabileceği,
bu paketlerin {\em hangi seviyede} loglayacağı (\PVerb!DEBUG!, \PVerb!INFO!, vs)
ve mesajların yazıldığı log dosyasının hangi dizinde olduğu gibi ayarlar
belirlenir.
Demo'muzun yaptığı \PVerb!log4j.xml! ayarları JBoss'un kendi \textbf{ana} Log4J
ayarları ile (\PVerb!server/default/conf/log4j.xml! altında) {\em uyumlu}
çalışacak şekilde yazılmıştır. Bu kullanım şekli sayesinde, JBoss'un kendine
özel diğer loglama işlemleri halâ devam edecektir, fakat bunun üstüne bizim
uygulamamıza özel log'lar \PVerb!JBOSS/server/default/log/kitapdemo.log! altına
gider. Bu tür kullanım çoğu kurumsal uygulama'nın ihtiyacı olan bir kullanım
şeklidir. Projelerde genelikle JBoss'un kendi içinden gelen mesajlarının bilinen
bir log dosyasına (\PVerb!server/default/log/server.log!) gönderilmesini
istenir. Ek olarak kendi uygulamamızın logları ayrı bir dosyaya gitmesi
beklenir.
\subsubsection{MANIFEST.MF}
Bu dosyanın basmakalıp bir içeriği vardır. Örnek kodlarda göreceğiniz içerik her
proje için aynı olacaktır. Olduğu gibi kullanabilirsiniz.
\subsubsection{web.xml}
\ref{web:requirements} bölümünde gördüğümüz gibi, \PVerb!web.xml!'in bir Struts
projesinde önemli görevlerinden biri Struts'ı kullanmamızı sağlayan
\PVerb!ActionServlet! adlı merkezi class'ı JBoss'a tanıtmaktır. Buna ek olarak
Servlet filtreleri \PVerb!web.xml! içinde tanımlanır. Her uygulama için Servlet
filtresi gerekmeyebilir. Bizim uygulamamızda JSP ve Action bazında Türkçe
karakterleri destekleyebilmek için \PVerb!RequestCharacterEncodingFilter! adlı
filtreyi \PVerb!web.xml! içinde tanımladık.
Bunların haricinde, Struts bazlı bir sistem \PVerb!web.xml!'e ihtiyaç
duymayacaktır. Struts uygulamalarında iş mantığı Action nesnelerinde, ve diğer
tüm Web odaklı ayarlar (akış kontrolü, hata muamelesi, vs)
\PVerb!struts-config.xml! ayar dosyasında yapıldığı için, eski yöntem Model I ve
II uygulamalarında olduğu kadar \PVerb!web.xml! dosyasına ihtiyaç olmaz.
\subsection{HibernateSessionCloseFilter}
Hibernate'i kapsamlı olarak anlattığımız \ref{hibernate}. bölümde veri tabanı
ile işimiz bittiğinde bu durumu \PVerb!HibernateSession.commitTransaction()! ve
\PVerb!HibernateSession.closeSession()! belirteceğimizi söylemiştik. Fakat bu
şekildeki \PVerb!Session! ve \PVerb!Transaction! kullanımı Web ortamında
problemler doğuruyor.
Problemin çıkış noktası Struts Action'lar ve JSP sayfalarının içeriklerini
göstermesinde olan işleyiş sırasıdır. Eğer elimizde \PVerb!Garage! ve onun
üzerinde bir \PVerb!set! olarak tutulan \PVerb!Car! nesneleri var ise, tipik
olarak bir Struts Action ile bu listeyi alırız ve JSP ile sunum için bir
\PVerb!HttpSession! üzerine koyarız. Ve hemen arkasından (daha JSP bu listeyi
görmeden) Hibernate transaction commit edilir ve session kapatılır. Bunun
yapılma sebebi, elimizdeki son Java kodlama noktasının Action \PVerb!execute!
metotunun son satırı olmasıdır! JSP içine Java komutları koyamayız, çünkü View
ve Controller kavramlarını birbirine karıştırmamak gerekir.
En sonunda işlem sırası JSP'ye geldiğinde ve sayfanın listeye bakması
gerektiğinde, elinde daha içerikleri somutlanmamış bir \PVerb!Car! listesi
olacaktır. Bu listenin içeriğin erişmeye çalıştığınız anda, Hibernate
\PVerb!LazyInitializationException! hatasını verir
\cite[sf. 300]{hibernatebook}, çünkü Hibernate elindeki \PVerb!Car! nesnelerinin
içeriğini doldurmaya uğraşmaktadır, ama elinde bunu yapacak Hibernate session yoktur.
Bu hatadan kurtulmak için, evet, bazı Hibernate ayarlarıyla oynamak suretiyle
bir anda yükleme (fetching) seviyesini arttırabilir, ve \PVerb!Car! listesi
alındığında \PVerb!Car! nesnelerinin yüklenmesini zorlayabiliriz. Ya da, listeyi
alınca Action içinden elle/zorla bu listeyi {\em gezerek} \PVerb!Car!'ların
yüklenmesini zorlayabiliriz. Fakat bu iki seçimden birincisi Web dünyasının bir
gerekliliğini eşleme dosyaları üzerine yansıtarak ileride yapabileceğiniz
performans ayarlarlama (tuning) manevra alanınızı kısıtlar. İkinci seçenek ise,
elle yazılmış, fazla ve gereksiz bir koddur (Kural \#7 ihlâli).
Tavsiyemiz Web'e özel bir problemin Web'e özel ve {\em tek} bir yerde
çözülmesidir. Servlet filtreleri burada yardımımıza yetişiyor. Altta gösterilen
filtre Hibernate transaction'ı commit etme ve session'ı kapatma işini {\em JSP
gösterimi bittikten sonra} yapar. Servlet işleyiş kurallarına göre,
\PVerb!chain.doFilter! çağrısı geri geldikten sonra, JSP görüntülenmesi bitmiş
demektir. Bu nokta da Hibernate kapanış işlemlerini yapmak için en uygun yerdir.
\begin{lstlisting}[language=Java,caption=HibernateCloseSessionFilter.java]
public class HibernateCloseSessionFilter implements Filter {
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException,
ServletException
{
try {
chain.doFilter(request, response);
HibernateSession.commitTransaction();
} finally {
HibernateSession.closeSession();
}
}
public void destroy() { }
}
\end{lstlisting}
\begin{lstlisting}[language=XML,caption=web.xml]
<web-app>
...
<filter>
<filter-name>HibernateCloseSessionFilter</filter-name>
<filter-class>
org.mycompany.kitapdemo.util.HibernateCloseSessionFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>HibernateCloseSessionFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
...
</web-app>
\end{lstlisting}
Bu ayarlardan sonra, artık Struts Action kodlarında \PVerb!commit! ve
\PVerb!close! işlemlerini yapmamıza gerek kalmaz. Hibernate kapanış işlemleri
kaç tane Struts Action işlemiş olursa olsun JSP sayfasının görüntülenmesi
bittiğinde hemen devreye sokulacaktır.
\subsection{Hızlı Geliştirme}
Kitap örneklerimizin hepsi geliştirme ortamında Ant programını kullanmaktadır
(Ant hakkında ek detayları \ref{install:ant} bölümünde bulabilirsiniz). Ant,
aynen make gibi, bir komut dosyası kullanır; \PVerb!build.xml! dosyasında
derleme (compilation), test, deployment gibi geliştirme sürecinde lazım olacak
tüm işlemler yazılmış hâlde bulunur. Demo'muz için hazırlanan Ant
\PVerb!build.xml! dosyaları birçok projeden ders alınarak hazırlanmıştır (bkz
\ref{install:samples} bölümü). Pek çok projede gereken hızlı geliştirme desteği,
yâni sadece değişen dosyaların derlenmesi ve deploy edilmesi
\PVerb!build.xml!'deki \PVerb!compile! ve \PVerb!dist! hedefleriyle
sağlanmıştır. Sadece değişen kodların derlenmesi oldukça açık olduğu için bu
konu detayına girmeyeceğiz. Hızlı deployment desteği şöyledir: Eğer geliştirme
sırasında sadece JSP kodu değiştirdiyseniz,
\begin{lstlisting}[language=sh, frame=none]
> ant dist
\end{lstlisting}
komutunu kullanarak sadece değişen JSP dosyalarını hedef JBoss dizinine
gönderebilirsiniz. JBoss, değişen JSP dosyalarını anında işleme koyabileceği
için yeni JSP dosyalarını test etmek için Uygulama Servisi'ni kapatıp/açmanıza
gerek kalmaz.
Ne yazık ki aynı tekniği normâl Java kodları (\PVerb!class! dosyaları) için
kullanamıyoruz (ki bu durum piyasadaki tüm Uygulama Servisleri için
geçerlidir). Java ClassLoader kullanımı ile alakalı bir durum yüzünden, yeni
derlenmiş Java class kodlarını JBoss çalışırken sonuç dizinine göndermek,
Uygulama Servisinin yeni kodları işleme koymasını sağlamaz. Yeni kodların
görülmesi için, deployment sonrasında Uygulama Servisini kapatıp/açmanız
gerekmektedir.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%5
\section[Türkçe Karakter Desteği][TÜRKÇE KARAKTER DESTEĞİ]{Türkçe Karakter Desteği}
Daha ileri gitmeden ``Web Uygulamarında Türkçe Karakter Sorunu'' başlıklı sorunu
işlememiz ve çözmemiz gerekiyor. Her seviyeye ve katmanı ilgilendiren bu sorunu
çözer çözmez, iş mantığı odaklı Struts tekniklerine devam edebileceğiz.
İlk önce terminoloji: Literatürde internationalization gibi çok uzun bir kelime
yerine genelde i18n ibaresi kullanılır, çünkü internationalization kelimesinin
ilk i ve son n harfi arasından 18 tane harf vardır; Kısaca bu kelimeye i18n
denmiştir. Biz de yazının geri kalanında i18n kelimesini kullanacağız.
i18n, uygulamanızın {\em her seviyesinde} ayrı bir şekilde çözmeniz gereken bir
sorundur. Daha basit olan \PVerb!StrutsHibSimple! uygulamasından daha zor olan
\PVerb!StrutsHibTag! uygulamasına terfi ederken, özel olarak Türkçe karakter
desteğinin genel olarak i18n probleminin hangi noktalara etki ettiğini teker
teker göreceğiz. Tüm çözümü birarada \PVerb!StrutsHibTag! örneğinin kodlarında
bulabilirsiniz.
\subsection{Apache}
HTML belgelerinin söylediğinin aksine, HTML sayfalarımızın başında
\begin{lstlisting}[language=Java, frame=none]
<META http-equiv="Content-Type" content="text/html; charset=utf-8"/>
\end{lstlisting}
tanımı kullanmak, \PVerb!utf-8! karakteri kodlaması kullanmak için yeterli
olmamaktadır. Apache'nin her HTML sayfasını \PVerb!utf-8! ile kodlaması için,
\PVerb!httpd.conf! dosyasındaki \PVerb!<VirtualHost>! etiketi içine
\begin{lstlisting}[language=Java, frame=none]
AddDefaultCharset utf-8
\end{lstlisting}
satırını eklemeniz gerekmektedir.
\subsection{Http Request}
Bir Web uygulamasının Türkçe karakterleri ile çalışabilmesi için Java
seviyesinde \PVerb!request! nesnesi ve JSP sayfaları üzerinde karakter
kodlamasını (character encoding) değiştirmemiz gerekiyor. Bu iki kodlamayı
\PVerb!UTF-8! bazlı yapmamız gerekmektedir.
\PVerb!Request! üzerinde yapılması gereken değişikliği her Struts Action class'ı
içinden yapabilirdik, fakat bu aynı kodun çok fazla tekrar etmesi demek
olacaktır, ve bu Kural \#7'nın ihlâli olurdu. Tekrarın her türlüsünü ortadan
kaldırmak istediğimiz için, tüm \PVerb!request! bazlı karakter kodlamasını tek
bir Servlet filtresi ile yapabiliriz. Bu filtre
\PVerb!RequestCharacterEncodingFilter! adlı filtredir (\PVerb!StrutsHibSimple!
kodları içinde bulunabilir). Filtreyi işleme koymak için \PVerb!web.xml!'de
alttaki gibi bir değişiklik yeterli olacaktır.
\begin{lstlisting}[language=XML, frame=none]
<web-app>
<display-name>KitapDemo</display-name>
<filter>
<filter-name>RequestCharacterEncodingFilter</filter-name>
<filter-class>
org.mycompany.kitapdemo.util.RequestCharacterEncodingFilter
</filter-class>
<init-param>
<param-name>requestCharacterEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>RequestCharacterEncodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
....
</web-app>
\end{lstlisting}
Java Servlet standartına göre bir filtre class'ı sistemimizdeki herhangi bir
Servlet (ve bilahere Struts Action) class'ı işletilmeden bile {\em önce} işleme
konur. Bu an, istediğimiz karakter kodlaması değişikliğini yapmak için harika
bir andır. Daha Servlet bile \PVerb!request! nesnesine bakmadan karakter
kodlama değişikliğini tek bir yerden yapabilmiş oluruz. Bir Servlet filtresi her
\PVerb!request! üzerinde işletilir, bu sebeple kodlama değişikliği her Servlet
ve her Action için otomatik olarak yapılmış olacaktır. Böylece her Action
üzerinde sürekli tekrar eden basmakalıp kodları yazmaktan kurtulduk (Kural \#7).
\begin{figure}[!hbp]
\center{
\scalebox{0.65}{
\includegraphics{./images/filter.eps}
}
}
\caption{Servlet Filtresi}
\end{figure}
\begin{lstlisting}[language=Java, caption=RequestCharacterEncodingFilter.java]
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class RequestCharacterEncodingFilter implements Filter {
public static final String REQUEST_CHARACTER_ENCODING =
"requestCharacterEncoding";
private String encoding = null;
public void init(FilterConfig filterConfig) throws ServletException
{
encoding = filterConfig.getInitParameter(REQUEST_CHARACTER_ENCODING);
}
private String getInitParameter(FilterConfig filterConfig,
String parameterName)
throws ServletException
{
String value = filterConfig.getInitParameter(parameterName);
if (StringUtils.isEmpty(value)) {
throw new ServletException(getClass().getName() +
": " +
parameterName +
" is required");
}
return value;
}
public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException,
ServletException
{
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
public void destroy() { }
}
\end{lstlisting}
Filtre için gereken kodlama parametresi \PVerb!web.xml! içinden (\PVerb!UTF-8!
değeri) \PVerb!init-param! kullanılarak geçilmiştir. Değerin ``kod içinden''
alınmasını filtre içindeki \PVerb!getInitParameter! metotu
hallediyor. Parametrenin ismini aldıktan sonra
\begin{lstlisting}[language=Java, frame=none]
filterConfig.getInitParameter(``requestCharacterEncoding'')!
\end{lstlisting}
çağrısını yaparak, gereken parametre değeri okunup,
\PVerb!request.setCharacterEncoding! ile işleme konmaktadır.
\subsection{JSP}
JSP sayfasının Türkçe karakterleri gösterebilmesi için sayfa kodlamasının (page
encoding) değişmesi gerekmektedir. Bu değişim, her sayfada yapılmalıdır. O zaman
her sayfanın başına \PVerb!UTF-8! kodlamasını kullanmak istediğimizi belirten
bir ibare koymamız gerekiyor\footnote{Bulut F. Ersavaş,
\url{http://www.teknoturk.org/docking/yazilar/tt000144-yazi.htm}.}. Bu da şöyle
yapılır:
\begin{lstlisting}[language=XML, frame=none]
<META http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<%@ page language="java" contentType="text/html;
charset=UTF-8" pageEncoding="UTF-8"%>
\end{lstlisting}
\subsection{Struts Resources}
Struts uygulamalarında JSP sayfasında dinamik olmayan sabit alan tanım değerleri
(input labels) (meselâ {\em isim}, {\em soyad} gibi tarif değerleri) direk JSP
içine gömülebilir. Fakat, değişik dilde müşteriye servis etmemiz gerektiği zaman
bu tanım değerlerinin de dinamik bir şekilde (dilden dile) değişebilmesini
isteriz. O zaman, tanım değerlerinin her dil için değişik bir dosyadan gelmesini
sağlamamız gerekiyor.
Struts bu türden bir değişimi uygulama seviyesindeki {\em ayar dosyasının
seçimini} dile bağlı olarak yapabilmekle destekler. \PVerb!StrutsHibSimple!
örneğinde sonuç dizini \PVerb!WEB-INF\classes! altında
\PVerb!application.resources! adlı dosyada, uygulamamız için gerekli hata
mesajlarını koymuştuk. Aslında bu dosya içine {\em istediğimiz her tanımı}
koyabileceğimiz bir yerdir. Gerekli tanım, normâlde JSP içine gömülen alan tanım
değerleri olabilir. Bu yapılınca bu dosya içindeki tanımlara JSP içinden
\PVerb!bean:message! Struts etiketi ile erişebiliriz. Daha önce
\begin{lstlisting}[language=XML, frame=none]
<tr>
<td>
License Plate
</td>
<td>
<html:text property="licensePlate" size="32" />
</td>
</tr>
<tr>
\end{lstlisting}
gibi gömülmüş değer kullanmak yerine, artık
\begin{lstlisting}[language=XML, frame=none]
<tr>
<td>
<bean:message key="main.license.plate"/>
</td>
<td>
<html:text property="licensePlate" size="32" />
</td>
</tr>
<tr>
\end{lstlisting}
kullanabiliriz. JSP kodu, bu sayede, hem İngilizce hem Türkçe için aynı
kalır.
Bu yapıldıktan sonra,tanımların değişik bir dilde (meselâ Türkçe'de) değişik
çıkması için \PVerb!classes! dizini altına \PVerb!application_tr.properties!
adında yeni bir dosya koyarız. Bu dosyada, \PVerb!application.properties!'deki
her label için yeni dildeki karşılıklar konacaktır.
Artık tarayıcımızın dil seçimini değiştirdiğimiz anda, meselâ \PVerb!en!
English'den \PVerb!tr! Türkçe'ye geçtiğimiz zaman, Struts otomatik bir şekilde
\PVerb!application.properties! yerine \PVerb!application_tr.properties!
dosyasını seçmesi gerektiğini bilecektir.
Örnek olarak \PVerb!main.license.plate! tanımını alalım. İngilizce ve Türkçe
için iki ayrı dosya şöyle gözükecektir.
\begin{lstlisting}[language=XML,frame=none,caption=application.properties]
main.license.plate=License Plate
\end{lstlisting}
\begin{lstlisting}[language=XML,frame=none,caption=application\_tr.properties]
main.license.plate=Plaka
\end{lstlisting}
Tarayıcınızda gerekli değişikliği yapıp, tarayıcıyı açıp kapattığınızda ve
JSP'yi tekrar yüklediğinizde, İngilizce yerine Türkçe mesajların çıktığını
göreceksiniz.
\subsubsection{Resources Dosyası İçinde Türkçe Karakterler}\label{web:tr:resources}
Resources dosyası hakkında aşılması gereken bir daha handikap vardır.
\PVerb!application_tr.properties! dosyası içinde ne yazık ki üğişçö harflerinden
sadece ü, ç, ve ö harflerini direk kullanabiliyoruz. Diğer Türkçe karakterler
Struts tarafından ekrana yanlış basılmaktadır. Bu harflerin yerine
\ref{web:table:resources} tablosundaki kod değerlerini kullanmak zorundayız.
\begin{table}[!hbp]
\centering