1. مرشح Servlet
1.1 ما هو مرشح
المرشح هو برنامج يعمل على الخادم قبل صفحة Servlet أو JSP المرتبطة به. قد يتم إرفاق المرشحات بواحد أو أكثر من صفحات Servlets أو JSP وقد تحقق من المعلومات التي تدخل هذه الموارد. بعد ذلك ، يمكن تحديد المرشح على النحو التالي:
① استدعاء الموارد بطريقة منتظمة (أي استدعاء صفحات Servlets أو JSP).
② استخدم معلومات الطلب المعدلة للاتصال بالمورد.
exbly المورد ، ولكن قم بتعديله قبل إرسال الاستجابة إلى العميل.
④ قم بإلغاء استدعاء الموارد ، وبدلاً من ذلك ، انتقل إلى مورد آخر ، أو إرجاع رمز حالة معين أو إنشاء إخراج بديل.
1.2 المبادئ الأساسية لفلتر servlet
عند استخدام servlet كمرشح ، يمكنه معالجة طلبات العملاء. بعد اكتمال المعالجة ، سيتم تسليمها إلى المرشح التالي للمعالجة ، بحيث تتم معالجة طلب العميل واحدًا تلو الآخر في سلسلة المرشح حتى يتم إرسال الطلب إلى الهدف. على سبيل المثال ، يحتوي موقع الويب على صفحة ويب يقدم "معلومات التسجيل المعدلة". بعد أن يملأ المستخدم المعلومات المعدلة ويقدمها ، يحتاج الخادم إلى القيام بمهمتين عند المعالجة: تحديد ما إذا كانت جلسة العميل صالحة ؛ وترميز البيانات المقدمة بشكل موحد. يمكن معالجة هاتين المهمتين في سلسلة مرشح تتكون من مرشحين. عندما تنجح عملية التصفية ، يتم إرسال البيانات المقدمة إلى الهدف النهائي ؛ إذا كانت عملية التصفية غير ناجحة ، فسيتم توزيع العرض على صفحة الخطأ المحددة.
2. خطوات تطوير مرشح Servlet
خطوات تطوير مرشح servlet هي كما يلي:
① اكتب فئة servlet التي تنفذ واجهة المرشح.
configigure filter في web.xml.
يتطلب تطوير مرشح تطبيق واجهة المرشح. تحدد واجهة المرشح الطرق التالية:
① يتم استدعاء Destory () بواسطة حاوية الويب لتهيئة هذا المرشح.
② init (FilterConfig FilterConfig) يتم استدعاؤه بواسطة حاوية الويب لتهيئة هذا المرشح.
③ Dofilter (طلب ServletRequest ، استجابة ServleTResponse ، سلسلة مرشحات المرشح) رمز معالجة تصفية محدد.
3. مثال على إطار المرشح
Simplefilter1.Java
package com.zj.sample ؛ استيراد java.io.ioException ؛ استيراد javax.servlet.filter ؛ استيراد javax.servlet.filterchain ؛ استيراد javax.servlet.filterConfig ؛ import javax.servletexception ؛ الطبقة العامة SimpleFilter1 تنفذ Filter {suppressWarnings ("غير مستخدمة") FilterConfig FilterConfig ؛ public void init (filterConfig config) يلقي servleTexception {this.filterConfig = config ؛ } public void dofilter (request servletRequest ، استجابة servletResponse ، سلسلة filterchain) {try {system.out.println ("داخل simplefilter1: تصفية الطلب ...") ؛ chain.dofilter (طلب ، استجابة) ؛ // أرسل المعالجة إلى نظام التصفية التالي. } catch (ioException ioe) {ioe.printstacktrace () ؛ } catch (servleTexception se) {se.printstacktrace () ؛ }} public void destroy () {this.filterConfig = null ؛ }}
Simplefilter2.java
package com.zj.sample ؛ استيراد java.io.ioException ؛ استيراد javax.servlet.filter ؛ استيراد javax.servlet.filterchain ؛ استيراد javax.servlet.filterConfig ؛ import javax.servletexception ؛ الطبقة العامة SimpleFilter2 تنفذ Filter {suppressWarnings ("غير مستخدمة") FilterConfig FilterConfig ؛ public void init (filterConfig config) يلقي servleTexception {this.filterConfig = config ؛ } public void dofilter (request servletRequest ، استجابة servletResponse ، سلسلة filterchain) {try {system.out.println ("داخل simplefilter2: تصفية الطلب ...") ؛ Chain.dofilter (طلب ، استجابة) ؛ // أرسل المعالجة إلى نظام التصفية التالي. } catch (ioException ioe) {ioe.printstacktrace () ؛ } catch (servleTexception se) {se.printstacktrace () ؛ }} public void destroy () {this.filterConfig = null ؛ }}
web.xml
<Ivilter> <ilter-name> filter1 </filter-name> <ilter-class> com.zj.sample.simplefilter1 </filter-class> </filter> <ilter-mapping> <lilter-name> filter1 </filter-name> <Url-pattern>/*</url-pattern> <Filter-Name> filter2 </filter-name> <ilter-class> com.zj.sample.simplefilter2 </filter-class> </filter> <filter mapping> <filter-name> filter2 </filedter-name> <url-patern>/*</url-pattern> // filter </filter </filter maping>
افتح أي صفحة في حاوية الويب لإخراج النتيجة: (لاحظ أمر الطلب/الاستجابة الذي تم تنفيذه بواسطة المرشح)
داخل SimpleFilter1: تصفية الطلب ... ضمن SimpleFilter2: تصفية الطلب ... ضمن SimpleFilter2: تصفية الاستجابة ... ضمن SimpleFilter1: تصفية الاستجابة ...
4. مرشح التقرير
دعنا نجرب مرشحًا بسيطًا يطبع رسالة إلى الإخراج القياسي عن طريق استدعاء صفحة Servlet أو JSP ذات الصلة. لتنفيذ هذه الوظيفة ، يتم تنفيذ سلوك التصفية في طريقة Dofilter. عندما يتم استدعاء صفحة Servlet أو JSP المرتبطة بهذا المرشح ، تقوم طريقة Dofilter بإنشاء نسخة مطبوعة تسرد المضيف المطلوب وعنوان URL للمكالمة. نظرًا لوجود طريقة getRequesturl في httpservletrequest بدلاً من servletrequest ، يتم إنشاء كائن servletrequest كنوع httpservletrequest. دعونا نغير Simplefilter1.java في الفصل 3.
Simplefilter1.Java
package com.zj.sample ؛ import java.io.ioException ؛ import java.util.date ؛ import javax.servlet javax.servlet.servletresponse ؛ استيراد javax.servlet.http.httpservletrequest ؛ الطبقة العامة SimpleFilter1 تنفذ Filter {suppressWarnings ("غير مستخدمة") FilterConfig FilterConfig ؛ public void init (filterConfig config) يلقي servleTexception {this.filterConfig = config ؛ } public void dofilter (request servletRequest ، استجابة servletResponse ، سلسلة filterchain) {try {system.out.println ("داخل simplefilter1: تصفية الطلب ...") ؛ httpservletrequest req = (httpservletrequest) طلب ؛ System.out.println (req.getRemoteHost () + "حاول الوصول إلى" + req.getRequesturl () + "on" + new Date () + ".") ؛ Chain.dofilter (طلب ، استجابة) ؛ System.out.println ("داخل SimpleFilter1: تصفية الاستجابة ...") ؛ } catch (ioException ioe) {ioe.printstacktrace () ؛ } catch (servleTexception se) {se.printstacktrace () ؛ }} public void destroy () {this.filterConfig = null ؛ }}
تبقى إعدادات web.xml دون تغيير ، في نفس الفصل 3.
امتحان:
أدخل [url] http: // localhost: 8080/test4jsp/login.jsp [/url]
نتيجة:
داخل SimpleFilter1: تصفية الطلب ... 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 0: 1 حاولت الوصول إلى [url] http: // localhost: 8080/test4jsp/login.js SimpleFilter2: تصفية الاستجابة ... داخل SimpleFilter1: تصفية الاستجابة ...
5. المرشحات عند الوصول (باستخدام servlets لتهيئة المعلمات في المرشحات)
فيما يلي تعيين نطاق زمني للوصول العادي باستخدام init لتسجيل الوصول الذي ليس في هذه الفترة الزمنية. دعونا نغير simplefilter2.java في الفصل 3.
Simplefilter2.java.
package com.zj.sample ؛ استيراد java.io.ioException ؛ استيراد java.text.dateformat ؛ استيراد java.util.calendar ؛ استيراد java.util.greasiancalendar ؛ import javax.servlet.filter ؛ import javax.servlet.filterchain ؛ import javax.servigt.filter.filter ؛ javax.servlet.servletcontext ؛ استيراد javax.servlet.servletexception ؛ استيراد javax.servlet.servletrequest ؛ استيراد javax.servlet.servletrespons الطبقة العامة SimpleFilter2 تنفذ Filter {suppressWarnings ("غير مستخدمة") FilterConfig config ؛ سياق servletContext الخاص ؛ Private Int StartTime ، endtime ؛ DateFormat Formatter ؛ init public void (filterConfig config) يلقي servleTexception {this.config = config ؛ context = config.getServletContext () ؛ formatter = dateformat.getDateTimeInstance (dateFormat.medium ، dateFormat.medium) ؛ جرب {starttime = integer.parseint (config.getInitParameter ("starttime")) ؛ // web.xml endtime = integer.parseint (config.getInitParameter ("Endtime")) ؛ // web.xml} catch (numberMatexception nfe) وقت البدء = 22 ؛ // 10:00 مساءً نهاية الوقت = 6 ؛ // 6:00 am}} public void dofilter (request servletRequest ، استجابة servletResponse ، سلسلة filterchain) {try {system.out.println ("داخل simplefilter2: تصفية الطلب ...") ؛ httpservletrequest req = (httpservletrequest) طلب ؛ GregorianCalendar Calendar = GregorianCalendar () جديد ؛ int currenttime = calendar.get (calendar.hour_of_day) ؛ if (isUnusualTime (currenttime ، startime ، endtime)) {context.log ("تحذير:" + req.getRemoteHost () + "تم الوصول إليه" + req.getRequesturl () + "on" + formatter.format (calendar.gettime ())) ؛ // ملف السجل تحت <catalina_home> /logs. One Log يوميًا. } chain.dofilter (طلب ، استجابة) ؛ System.out .println ("داخل SimpleFilter2: تصفية الاستجابة ...") ؛ } catch (ioException ioe) {ioe.printstacktrace () ؛ } catch (servleTexception se) {se.printstacktrace () ؛ }} public void Dride () {} // هل الوقت الحالي بين البداية والنهاية // الأوقات التي يتم تمييزها على أنها أوقات وصول غير طبيعية؟ isUnusualtime الخاص المنطقي الخاص (int currenttime ، int starttime ، int endtime) {// إذا كان وقت البدء أقل من وقت الانتهاء (أي ، // هم مرتين في نفس اليوم) ، فإن الوقت الحالي يعتبر غير عادي إذا كان // بين أوقات البداية والنهاية. if (startTime <endtime) {return ((currenttime> = StartTime) && (currenttime <endtime)) ؛ } // إذا كان وقت البدء أكبر من أو يساوي وقت النهاية // (أي ، يكون وقت البدء في يوم واحد و // في وقت الانتهاء في اليوم التالي) ، فإن الوقت الحالي // يعتبر غير عادي إذا لم يكن بين // أوقات البدء. آخر {return (! isUnusualTime (currenttime ، endtime ، startTime)) ؛ }}}
تبقى إعدادات web.xml دون تغيير.
فيما يتعلق بمعالجة سجل Tomcat ، إليك مقدمة أخرى. config.getServletContext (). سوف يكتب سجل ("رسالة السجل") معلومات السجل إلى مجلد <Catalina_home>/logs. يجب أن يكون اسم الملف LocalHost_Log.2007-03-04.txt (يتم إنشاء واحد يوميًا ، ويمكن رؤيته في اليوم التالي). للحصول على ملف السجل هذا ، يجب أن يكون لديك:
<logger className = "org.apache.catalina.logger.filelogger" prefix = "catalina_log." لاحقة = ". txt" timestamp = "true"/>
6. مرشحات الموقع محظورة
إذا كنت ترغب في مقاطعة عملية التصفية اللاحقة في منتصف الطريق عندما يكتشف المرشح الخاص بك استثناء غير طبيعي ، يمكنك القيام بذلك:
dofilter public void (طلب servletRequest ، استجابة servletResponse ، سلسلة filterchain) يلقي servletexception ، ioException {httpservletrequest req = (httpservletrequest) ؛ httpservletresponse res = (httpservletresponse) ؛ if (isUnusualCondition (req)) {res.SendRedirect ("http://www.somesite.com") ؛ } آخر {chain.dofilter (req ، res) ؛ }} المثال التالي هو مرشح موقع محظور. إذا كنت لا تريد أن تصل بعض المواقع إلى موقع الويب الخاص بك ، فيمكنك إدراج موقعه في القيمة المعلمة لـ web.xml ، ثم تطبيق المبدأ أعلاه للقفز من التصفية العادية وإعطاء الصفحة المحظورة.
bustaCaScessFilter.java
package com.zj.sample ؛ استيراد java.io.ioException ؛ استيراد java.io.printwriter ؛ استيراد java.net.malformedurlexception ؛ import java.net.url ؛ import java.util.hashset ؛ import java.util.StringTokenizer ؛ import javax.servelter ؛ javax.servlet.filterconfig ؛ استيراد javax.servlet.servletexception ؛ استيراد javax.servlet.servletrequest ؛ استيراد javax.servlet.servletrespons الطبقة العامة PrustAccessFilter تنفذ Filter {private hashset <string> budtsiteTable ؛ /*** رفض الوصول إذا كان الطلب يأتي من موقع بانر أو يتم إحالته هنا* بواسطة موقع بانر. */ public void dofilter (servletRequest request ، servletResponse ، سلسلة filterchain) يلقي servletexception ، ioException {system.out.println ("داخل buductaccessfilter: تصفية الطلب ...") ؛ httpservletrequest req = (httpservletrequest) طلب ؛ String requestinghost = req.getRemoteHost () ؛ string arvershost = getReferRinghost (req.getheader ("reparer")) ؛ سلسلة bantsite = فارغة ؛ منطقية isbired = false ؛ if (bustsiteTable.contains (requestinghost)) {bantsite = requestinghost ؛ isbired = true ؛ } if if (bustsiteTable.contains (reversionhost)) {bustsite = refcerhost ؛ isbired = true ؛ } if (isbired) {showWarning (response ، bantsite) ؛ } آخر {chain.dofilter (طلب ، استجابة) ؛ } system.out.println ("داخل bustaCAccessFilter: تصفية الاستجابة ...") ؛ } /*** إنشاء جدول من المواقع المبرمة بناءً على معلمات التهيئة. وبالتالي ، من الآمن استخدام hashset (الذي يحدد* ما إذا كان هناك مفتاح معين) بدلاً من علامة التجزئة الخاطئة* (التي لها قيمة لكل مفتاح).*/ public void init (filterConfig config) يرمي servleTexception {banneredSitable = new hassset <string> () ؛ String budtsites = config.getInitParameter ("budtsites") ؛ // مجموعة الرمز المميز الافتراضي: مساحة بيضاء. StringTokenizer Tok = New StringTokenizer (bustsites) ؛ بينما (tok.hasmoreTokens ()) {String bantsite = tok.nextToken () ؛ budtsiteTable.Add (bantsite) ؛ System.out.println ("حظر" + bustsite) ؛ }} public void Dride () {} private getReferRingHost (سلسلة refererringurlstring) {try {url revarendurl = url new (reflerRingUrlString) ؛ Return (reversionurl.gethost ()) ؛ } catch (malformedUrlexception mue) {// alformed أو null return (null) ؛ }} // استجابة الاستبدال التي يتم إرجاعها إلى المستخدمين // الذين هم من أو يشار إليها هنا بواسطة موقع لافتة. private void showwarning (servletResponse Response ، String bustsite) يلقي ServleTexception ، ioException {response.setContentType ("text/html") ؛ printWriter out = response.getWriter () ؛ String doctype = "<! doctype html public/"-// w3c // dtd html 4.0 " +" transitional // en/">/n" ؛ out.println (doctype + "<html>/n" + "<head> <title> الوصول المحظور </title> </head>/n" + "<bgcolor =/" white/">/n" + "<h1> محظور </h1>/n" + "آسف أو عن طريق" + bubledsite + " "</body> </html>") ؛ }}
web.xml
<Ivilter> <ilter-name> BUSTACCessFilter </filter-name> <filter-class> com.zj.sample.bluiveAccessfilter </filter-class> <Ing-param> <param-name> prantsites </param-name> [url] www.moreservlets.com [/url] 127.0.0.1//we اختبار هذا </param-value> </ith-param> </filter> <filter-mapping> <filter-name> budistaccessfilter </filter-name> <Url-pattern>
امتحان:
[url] http: // localhost: 8080/test4jsp/[/url]
نتيجة:
7. استبدال المرشح
7.1 تعديل الاستجابة
يمكن للمرشحات منع الوصول إلى الموارد أو منعها من التنشيط. ولكن إذا كان المرشح يريد تغيير الاستجابة الناتجة عن المورد. ما يجب القيام به؟ يبدو أنه لا توجد طريقة للوصول إلى الاستجابة الناتجة عن مورد. توفر المعلمة الثانية لـ Dofilter (servletResponse) طريقة لإرسال إخراج جديد إلى العميل ، ولكنه لا يوفر للمرشح وسيلة للوصول إلى إخراج صفحة Servlet أو JSP. لماذا هذا يحدث؟ نظرًا لأن صفحة Servlet أو JSP لم يتم تنفيذها عند استدعاء طريقة Dofilter لأول مرة. بمجرد استدعاء طريقة dofilter في كائن FilterChain ، يبدو أنه قد فات الأوان لتعديل الاستجابة ، وهو أنه تم إرسال البيانات إلى العميل.
ومع ذلك ، هناك طريقة ، أي تعديل كائن الاستجابة لطريقة Dofilter التي تم تمريرها إلى كائن Filterchain. بشكل عام ، قم بإنشاء ذاكرة التخزين المؤقت لجميع إصدارات الإخراج التي تم إنشاؤها بواسطة صفحة Servlet أو JSP. يوفر Servlet API الإصدار 2.3 موردًا مفيدًا لهذا ، وهو فئة HttPservletResponseWrapper. يتضمن استخدام هذه الفئة الخطوات الخمس التالية:
1) إنشاء غلاف استجابة. تمديد javax.servlet.http.httpservletResponseWrapper.
2) توفير طباعة طباعة التي تختدم الإخراج. overload the getWriter ، repring a printwriter يحفظ كل شيء يتم إرساله إليه ، ويحفظ النتيجة في حقل يمكن الوصول إليه لاحقًا.
3) تمرير هذا الغلاف إلى dofilter. هذه الدعوة قانونية لأن httpservletresponsewrapper تنفذ httpservletresponse.
4) استخراج وتعديل الإخراج. بعد استدعاء طريقة dofilter لـ FilterChain ، يمكن الحصول على إخراج المورد الأصلي باستخدام الآلية المقدمة في الخطوة 2. يمكنك تعديلها أو استبدالها طالما أنها مناسبة لتطبيقك.
5) إرسال الإخراج المعدل إلى العميل. نظرًا لأن المورد الأصلي لم يعد يرسل مخرجات إلى العميل (يتم تخزين هذه المخرجات بالفعل في غلاف الاستجابة) ، يجب إرسال هذه المخرجات. وبهذه الطريقة ، يحتاج المرشح الخاص بك إلى الحصول على printwriter أو outputstream من كائن الاستجابة الأصلي وتمرير الإخراج المعدل إلى الدفق.
7.2 غلاف استجابة قابل لإعادة الاستخدام
يعطي المثال التالي غلافًا يمكن استخدامه في معظم التطبيقات حيث يريد المرشح تعديل إخراج المورد. تعمل فئة chararraywrapper على زيادة تحميل طريقة getWriter لإرجاع طباعة طباعة تتراكم كل شيء في صفيف أحرف كبير. يمكن للمطورين الحصول على هذه النتيجة باستخدام Thararray (char char [] الأصلي) أو tostring (سلسلة مشتقة من char []).
chararraywrapper.java
package com.zj.sample ؛ استيراد java.io.chararrayWriter ؛ استيراد java.io.printwriter ؛ استيراد javax.servlet.http.httpservletresponse ؛ استيراد javax.servlet.http.htpservletresponswrapper ؛ /** * غلاف الاستجابة الذي يأخذ كل ما يخرجه العميل بشكل طبيعي ويقوم بحفظه في صفيف حرف واحد كبير. */Class Class ChararrayWrapper يمتد httpservletresponsewrapper {private chararraywriter charwriter ؛ /*** تهيئة الغلاف. * <p> * أولاً ، يستدعي هذا المُنشئ مُنشئ الأصل. هذه الدعوة *قاسية بحيث يتم تخزين الاستجابة ، وبالتالي Setheader و *setStatus و AddCookie وما إلى ذلك العمل بشكل طبيعي. * <p> * ثانياً ، يقوم هذا المُنشئ بإنشاء chararraywriter سيتم استخدامه لتجميع الاستجابة. */ public chararraywrapper (httpservletresponse response) {super (response) ؛ charwriter = new ChararRayWriter () ؛ } /*** عندما تسأل صفحات Servlets أو JSP للكاتب ، لا تمنحهم* الحقيقية. بدلاً من ذلك ، امنحهم نسخة تكتب في صفيف الأحرف. * يحتاج المرشح إلى إرسال محتويات الصفيف إلى العميل* (ربما بعد تعديله). */ printwriter public getWriter () {return (new printWriter (charwriter)) ؛ } /*** احصل على تمثيل سلسلة للمخزن المؤقت بأكمله. * <p> * تأكد من <b> ليس </b> للاتصال بهذه الطريقة عدة مرات على نفس الغلاف *. لا تضمن API لـ ChararRayWriter أنها "تتذكر" القيمة السابقة ، لذلك من المحتمل أن تجعل المكالمة * سلسلة جديدة في كل مرة. */ public string toString () {return (charwriter.toString ()) ؛ } /** احصل على صفيف الأحرف الأساسي. */ public char [] tochararray () {return (charwriter.tochararray ()) ؛ }}
7.3 استبدال المرشح
فيما يلي تطبيق شائع لـ chararraywrapper الواردة في القسم السابق: تغيير مرشح لسلسلة مستهدفة متعددة النقل إلى سلسلة بديلة.
7.3.1 مرشح الاستبدال العام
يعطي ReplyFilter.java مرشحًا يلف الاستجابة في chararraryWrapper ، يمرر التفاف إلى طريقة dofilter لكائن FilterChain ، ويستخرج قيمة نوع سلسلة إعطاء إخراج جميع الموارد ، ويحل محل جميع حوادث سلسلة مستهدفة مع سلسلة استبدال ، وترسل النتيجة المعدلة إلى العميل.
هناك شيئان يجب ملاحظته حول هذا المرشح. أولاً ، إنه فئة مجردة. لاستخدامه ، يجب عليك إنشاء فئة فرعية توفر تنفيذ طرق GetTargetString و GetReplacementString. ويرد مثال على هذا العلاج في القسم الفرعي التالي. ثانياً ، يستخدم فئة فائدة أصغر (انظر FilterUtils.java) لاستبدال السلسلة الفعلي. يمكنك استخدام حزم التعبير العادية الجديدة بدلاً من استخدام طرق منخفضة المستوى ومملة في السلسلة و stringtokenizer.
استبدال java
package com.zj.sample ؛ استيراد java.io.ioException ؛ استيراد java.io.printwriter ؛ استيراد javax.servlet.filter ؛ استيراد javax.servlet.filterchain ؛ استيراد javax.servlet.filterConfig ؛ import javax.servled.servletexception ؛ javax.servlet.servletresponse ؛ استيراد javax.servlet.http.httpservletresponse ؛ /*** مرشح يحل محل جميع حوادث سلسلة معينة مع استبدال*. * هذه فئة مجردة: يجب أن تتغلب </i> على طرق getTargetString* وطرق getReplacementsTring في فئة فرعية.* أول هذه الطرق تحدد السلسلة في الاستجابة* التي يجب استبدالها. الثانية من هذه المواصفات السلسلة* التي يجب أن تحل محل كل حدوث السلسلة الهدف. */Class Public Abstract Class ReplaceFilter Firements filter {private filterConfig config ؛ Public Void dofilter (طلب ServletRequest ، استجابة ServleTResponse ، سلسلة مرشحات المرشح) يلقي servletexception ، ioException {chararraywrapper reponseWrapper = new ChararrayWrapper ((httpservletresponse)) ؛ // استدعاء المورد ، وتراكم الإخراج في الغلاف. Chain.dofilter (طلب ، استجابة reclapper) ؛ // تحويل الإخراج بأكمله إلى سلسلة كبيرة واحدة. string reverseString = responseWrapper.toString () ؛ // في الإخراج ، استبدل جميع حوادث سلسلة الهدف مع الاستبدال // السلسلة. Responsestring = filterUtils.replace (الإجابة ، getTargetString () ، getReplacementString ()) ؛ // تحديث رأس طول المحتوى. updateHeaders (الاستجابة ، الاستجابة) ؛ printWriter out = response.getWriter () ؛ out.write (الاستجابة) ؛ } /*** قم بتخزين كائن FilterConfig في حالة رغبة الفئات الفرعية. */ public void init (filterConfig config) يلقي servletexception {this.config = config ؛ } FilterConfig GetFilterConfig () {return (config) ؛ } public void Dride () {} /*** السلسلة التي تحتاج إلى استبدال.* تجاوز هذه الطريقة في الفئة الفرعية الخاصة بك. */ السلسلة المجردة العامة getTargetString () ؛ /*** السلسلة التي تحل محل الهدف. تجاوز هذه الطريقة في * الفئة الفرعية الخاصة بك. */ السلسلة المجردة العامة getReplacementString () ؛ /*** يقوم بتحديث رؤوس الاستجابة. يعين هذا الإصدار البسيط فقط* رأس طول المحتوى ، على افتراض أننا نستخدم مجموعة أحرف* تستخدم 1 بايت لكل حرف.* بالنسبة لمجموعات الأحرف الأخرى ، تجاوز هذه الطريقة لاستخدام* منطق مختلف أو للتخلي عن اتصالات HTTP المستمرة.* في هذه الحالة الأخيرة ، قم بتعيين رأس الاتصال* على "الإغلاق". */ public void updateHeaders (servletResponse response ، string reversestring) {response.setContEntLength (responstring.length ()) ؛ }}
FilterUtils.java
حزمة com.zj.sample ؛ /*** فائدة صغيرة للمساعدة في أغلفة الاستجابة التي تعيد السلاسل. * /مرشحات الفئة العامة { /*** قم بتغيير جميع حوادث الأصل في Mainstring لاستبدالها. */ السلسلة الثابتة العامة استبدال (السلسلة الرئيسية ، أصول السلسلة ، استبدال السلسلة) {string result = "" ؛ int oldindex = 0 ؛ int index = 0 ؛ int Origlength = Orig.Length () ؛ بينما ((index = mainstring.indexof (Orig ، OldIndex))! = -1) {result = result + mainstring.substring (oldindex ، index) + replacement ؛ OldIndex = index + Origlength ؛ } النتيجة = النتيجة + mainstring.substring (OldIndex) ؛ العودة (نتيجة) ؛ }} 7.3.2 تنفيذ مرشح استبدال الأحرف. افترض أن Baidu قد حصلت على Google (مجرد فرضية) ، يجب استبدال جميع النصوص مع كلمة Google على جميع الصفحات بواسطة Baidu! replaceStInameFilter.java يرث replacefilter.java أعلاه لتنفيذ هذه الوظيفة. replaceStInameFilter.javapackage com.zj.sample ؛ تمتد الفئة العامة بدائل STINAMEFILTER ReplaceFilter {public string getTargetString () {return ("google.com.cn") ؛ } السلسلة العامة getReplacementString () {return ("baidu.com") ؛ }}
web.xml
<Ivilter> <ilter-name> placeSiteNameFilter </filter-name> <filter-class> com.zj.sample.replacesiteNameFilter </filter-class> </filter> <filter mapping> <lipter-name> absiteNameFilter </filter-name>
نتائج الاختبار:
قبل التصفية
بعد التصفية
8. مرشح الضغط
هناك العديد من المتصفحات الأخيرة التي يمكنها التعامل مع المحتوى المضغوط ، وتفريغ الملف المضغوط تلقائيًا باستخدام GZIP كقيمة رأس استجابة ترميز المحتوى ، ثم معالجة النتائج تمامًا مثل المستند الأصلي. يمكن أن يؤدي إرسال مثل هذا المحتوى المضغوط إلى توفير الكثير من الوقت ، لأن الوقت الذي يستغرقه ضغط مستند على الخادم ثم التراجع عن المستند على العميل أمر تافلي مقارنة بالوقت الذي يستغرقه تنزيل الملف. يمنح البرنامج Longservlet.java servlet مع إخراج نص عادي طويل مكرر ، و servlet ناضجة للضغط. إذا كنت تستخدم GZIP ، فيمكنه ضغط الإخراج إلى 1/300!
عندما يدعم المتصفح قدرة الضغط هذه ، يمكن لمرشح الضغط استخدام ChararrayWrapper الذي تم تقديمه في الفصل 7 لضغط المحتوى. المحتوى التالي مطلوب لإكمال هذه المهمة:
1) الفئة التي تنفذ واجهة المرشح. يدعى هذا الفئة CompressionFilter. تقوم طريقة init بتخزين كائن FilterConfig في حقل في حالة حاجة الفئة الفرعية إلى الوصول إلى بيئة Servlet أو اسم المرشح. جسم الأسلوب القدر فارغ.
2) كائن الاستجابة ملفوف. تلتف طريقة Dofilter كائن ServletResponse في chararraywrapper وتجاوز هذا الغلاف على طريقة dofilter لكائن filterchain. بعد اكتمال هذه المكالمة ، تم تنفيذ جميع المرشحات الأخرى والموارد النهائية والإخراج ضمن الغلاف. وبهذه الطريقة ، يستخرج Dofilter الأصلي مجموعة من الأحرف التي تمثل إخراج جميع الموارد. إذا ذكر العميل أنه يدعم الضغط (أي أخذ GZIP كقيمة لرأس القبول) ، فإن الفلتر يلحق gzipoutputstream إلى bytearrayoutputstream ، ونسخ مجموعة الأحرف إلى هذا الدفق ، ويعين رأس استجابة ترميز المحتوى إلى GZIP. إذا كان العميل لا يدعم GZIP ، فقم بنسخ مجموعة الأحرف غير المعدلة إلى BytearRayoutputStream. أخيرًا ، يرسل Dofilter النتيجة إلى العميل عن طريق كتابة صفيف الأحرف بأكمله (ربما مضغوط) في OutputStream المرتبط بالاستجابة الأصلية.
3) تسجيل Longservlet.
CompressionFilter.Java
package com.zj.sample ؛ استيراد java.io.bytearrayoutputstream ؛ استيراد java.io.ioException ؛ استيراد java.io.outputstream ؛ استيراد java.io.outputstreamwriter javax.servlet.filterconfig ؛ استيراد javax.servlet.servletexception ؛ استيراد javax.servlet.servletrequest ؛ استيراد javax.servlet.servletresponse ؛ استيراد javax.servlet.http.httpservlest ؛ /** * تصفية التي تضغط الإخراج باستخدام GZIP (على افتراض أن المتصفح يدعم * GZIP). */public Class CompressionFilter تنفذ filter {private filterConfig config ؛ /*** إذا كان المتصفح لا يدعم GZIP ، فاستدعاء المورد بشكل طبيعي. إذا كان المتصفح * <i> لا يدعم GZIP ، فقم بتعيين رأس استجابة ترميز المحتوى و * استدعاء المورد مع استجابة ملفوفة تجمع جميع الإخراج. * استخراج الإخراج واكتبه في صفيف بايت Gzipped. أخيرًا ، اكتب * هذا الصفيف إلى دفق إخراج العميل. */ public void dofilter (servletRequest request ، servletResponse ، سلسلة filterchain) يلقي servletexception ، ioException {httpservletrequest req = (httpservletrequest) ؛ httpservletresponse res = (httpservletresponse) ؛ if (! isgzipsupported (req)) {// استدعاء المورد بشكل طبيعي. Chain.dofilter (REQ ، Res) ؛ } آخر {// tell browser أننا نرسل بيانات gzipped. Res.Setheader ("ترميز المحتوى" ، "gzip") ؛ // استدعاء المورد ، وتراكم الإخراج في الغلاف. chararraywrapper reponseWrapper = new ChararrayWrapper (res) ؛ Chain.Dofilter (REQ ، ResponseWrapper) ؛ // الحصول على صفيف حرف يمثل الإخراج. char [] responsechars = responseWrapper.tochararray () ؛ // اصنع كاتبًا يضغط البيانات ويضعها في صفيف بايت. bytearrayoutputstream bytestream = جديد bytearrayoutputstream () ؛ gzipoutputstream zipout = gzipoutputstream جديد (bytestream) ؛ OutputStreamWriter tempout = new OutputStreamWriter (zipout) ؛ // ضغط الإخراج الأصلي ووضعه في صفيف البايت. tempout.write (responsechars) ؛ // يجب أن تكون تدفقات GZIP مغلقة بشكل صريح. tempout.close () ؛ // تحديث رأس طول المحتوى. res.setContentLength (bytestream.size ()) ؛ // إرسال نتيجة مضغوطة إلى العميل. outputStream realout = res.getOutputStream () ؛ bytestream.writeto (realout) ؛ }} /*** قم بتخزين كائن FilterConfig في حالة رغبة الفئات الفرعية. */ public void init (filterConfig config) يلقي servletexception {this.config = config ؛ } FilterConfig GetFilterConfig () {return (config) ؛ } public void Dorner () {} private boolean isgzipsupported (httpservletrequest req) {string prowserencodings = req.getheader ("accept-encoding") ؛ العودة ((BrowserenCodings! = null) && (browserencodings.indexof ("gzip")! = -1)) ؛ }}} longservlet.javapackage com.zj.sample ؛ import java.io.ioException ؛ import java.io.printWriter ؛ import javax.servlet.servletexception ؛ import javax.servlet.http.httpservlet ؛ import javax.servlet.htttp.htttplet javax.servlet.http.httpservletresponse ؛ /*** servlet مع الإخراج <b> Long </b>. تستخدم لاختبار تأثير مرشح الضغط * من الفصل 9. */ الطبقة العامة LongServlet يمتد httpservlet {public void doget (httpservletrequest request ، httpservletresponse) يلقي servletexception ، ioException {response.setContenttype ("text/ html") ؛ printWriter out = response.getWriter () ؛ String doctype = "<! doctype html public/"-// w3c // dtd html 4.0 " +" transitional // en/">/n" ؛ عنوان السلسلة = "صفحة طويلة" ؛ out.println (doctype + "<html>/n" + "<head> <title>" + title + "</title> </head>/n" + "<Body bgColor =/"#fdf5e6/">/n" + "<h1 align =/" center/">" خط سلسلة = "بلاه ، بلاه ، بلاه ، بلاه ، بلاه. لـ (int i = 0 ؛ i <10000 ؛ i ++) {out.println (line) ؛ } out.println ("</body> </html>") ؛ }}
web.xml
<Ivilter> <ilter-name> compressionfilter </filter-name> <ilter-class> com.zj.sample.compressionfilter </filter-class> </filter> <filter mapping> <filter-name> compressionfilter </filter-name> <Srevlet-Name> longservlet </servlet-name> <Servlet-class> com.zj.sample.longservlet </servlet-class> </servlet> <stervlet-mapping> <Servlet-name> longservlet </radle-name> <url-patern>/londservlet </url-patern>