1. الخلفية
المقال الذي كتبته هنا هو أن أحد الأصدقاء سأل عن الفرق بين الاستثناء الذي تم فحصه والاستثناء الذي لم يتم التحقق منه في Java. كانت إجابتي على ذلك: أنا فقط أستخدم RunTimeException عند البرمجة. في الواقع ، لدي فرضية عندما أقول شيئًا. يجب أن أقول ذلك بالضبط: أنا فقط استخدم أو انتبه فقط إلى RunTimeException عند كتابة رمز العمل ضمن إطار تطوير ناضج. لأنه نظرًا لأن الأطر غالبًا ما تتغلف الاستثناءات بشكل موحد ، بحيث يمكن للمبرمجين إيلاء اهتمام أفضل لرمز الأعمال ، وعادة ما تحدث بعض أخطاء العمل أثناء تشغيل النظام ، عادة ما يتم تصميم استثناءات العمل على أنها فئات فرعية من RunTimeException.
من الواضح أن إجابتي لا يمكن أن ترضي أصدقائي! لأنه ، بغض النظر عن من هو المبتدئ في Java ، فإننا نستخدم الكثير من المحاولة ... عندما نتعلم فصول IO وبرمجة JDBC ، هذا النوع من المحاولة المتكررة ... سيجعلنا نتذكر استثناءات Java! غالبًا ما لا يعرف المبتدئون سبب تصميم استثناءات Java مثل هذا. عادة ما يقومون بمعالجة الاستثناءات ببساطة - ما عليك سوى طباعة الاستثناءات في كتلة الصيد ، والبيان الأكثر استخدامًا هو:
E.PrintStackTrace ().
لدينا أيضًا استثناءات مثل الذاكرة مثل حدود عبور الصفيف:
java.lang.arrayindexoutofboundsexception: 6
سيجعلنا هذا أيضًا نتذكره جديدًا ، لأنه يظهر في كثير من الأحيان عندما نلاحظ البرنامج! سنجد أن هذا النوع من الاستثناء لا يحتاج إلى استخدام Try ... catch ... للقبض عليه في الكود.
مثالان أعلاه هما الاستثناء الذي تم فحصه في الواقع واستثناء غير محدد من قبل صديق. الاستثناء الذي يتطلب المحاولة ... الصيد ... هو الاستثناء الذي تم فحصه ، والاستثناء غير المحدد هو الاستثناء الذي لم يتم التحقق منه. إذا أردت التحدث عن خلافاتهم ، أقول إن أحدهم يريد أن يحاول ... التقاط ... والآخر لا يحتاج إليها. هل هذه الإجابة جيدة؟ أعتقد أن هذه الإجابة شاحبة. سيقول بعض الطلاب أيضًا أن المحاولة ... من الواضح أن Catch هو متصل طريقة يجبر الاستثناء الذي يتم إلقاؤه بشكل صريح. هل يعتبر E.PrintStackTrace () استثناءات معالجة؟ أعتقد أن هذه مجرد وسيلة بسيطة وكسول للتعامل معها! فما نوع طريقة التعامل مع ذكية؟ يتوقع مصمم لغة Java فعليًا أنه بعد حدوث استثناء ، يمكن للمتصل استعادة الاستثناء في الصيد حتى يتمكن البرنامج من الاستمرار في التنفيذ. ومع ذلك ، "المبرمجين الأذكياء كسول." هيه. في معظم الحالات ، نختار تسجيل السجلات ومطالبات مستخدم واجهة المستخدم بعد ظهور الاستثناء. في وقت لاحق ، سأجمع بين إطار Jersey للحديث عن معالجة الاستثناء الموحدة. بعد قراءة هذا ، سيقول بعض الأشخاص أن الفرق بين الاستثناء الذي تم فحصه والاستثناء غير المحدد هو أنه يجب معالجة الشخص والآخر لا يحتاج إلى معالجته. هل هذه الإجابة صحيحة؟ أعتقد أنه من الخطأ! وجهة نظري هي: علينا أن نتعامل معها سواء كان استثناءً محددًا أو استثناءًا غير محدد!
في الفقرة السابقة ، ما زلنا لا نحل الفرق بين الاستثناء الذي تم فحصه والاستثناء غير المحدد. لا أعتقد أنه من المهم إعطاء الإجابة. المهم هو كيفية التعامل مع هذه الاستثناءات وكيف نستخدم الاستثناءات أثناء التطوير.
وجهة نظري هي (تطوير نظام الويب):
1. قم بتغليف الاستثناء الذي تم فحصه على مستوى الإطار وتحويله إلى استثناء لم يتم التحقق منه لتجنب كتابة محاولة مملة ... رمز الصيد أثناء التطوير.
2. تطوير مستوى العمل ، يحدد عمليات RunTimeExceptions المختلفة وفقًا لمسؤوليات رمز البرنامج (إنه استثناء غير مرغوب فيه ، يتم تعريفه بشكل عام على أنه فئة فرعية من RunTimeException)
3. من خلال أول عرضين ، لن يكون للاستثناءات المخصصة في النظام سوى استثناءات غير محددة ، وسيكون النظام فقط في الطبقة العليا من بيانات تبادل العميل ، وإعداد آلية معالجة الاستثناءات الموحدة ، وتحويل بعض الاستثناءات إلى معلومات يمكن للمستخدمين فهمها ونقلها إلى المستخدمين.
4. آخرون مثل طبقة العمل ، وطبقة استمرار البيانات ، وما إلى ذلك ، تكون مسؤولة فقط عن إلقاء الاستثناءات ، ولكن احرصوا على عدم فقدان مكدس الاستثناء (هذا خطأ يكون المبتدئين معرضًا للإنشاء).
الخلفية طويلة بما فيه الكفاية! دعنا نصل إلى النقطة ونرى كيف يتم استخدام معالج الاستثناء الموحد لإطار Jersey!
2. استثناء موحد آلية معالجة جيرسي إطار عمل
هناك الاتفاقات التالية:
1. يستخدم المثال إصدار jersey1.x
2. إصدار الربيع هو 2.5
3. بالنسبة للبساطة ، لا يستخدم مشروع العينة آلية Maven
مثال وصف سيناريو العمل:
1. نقرأ ملف تكوين الخصائص ، ومحتوى ملف التكوين هو:
key1 = hello key2 = iteye.com
2. ابدأ الحصول على طلب http: // localhost: 8888/a/resources/test؟ n = 11 ، ويتطلب أن يكون n رقمًا ويجب أن يكون أقل من 10. إذا كان n خاطئًا ، فسيتم إنشاء خطأ استثناء غير محدد.
3. في هذا المثال ، ستقرأ طبقة الوصول إلى البيانات ملفًا ، وسيحدث خطأ استثناء محدد إذا تمت قراءة الملف.
تصميم هيكل مشروع العينة
وصف مقتطف رمز
1. ملف تخزين البيانات: test.properties
key1 = hello key2 = iteye.com
هذا هو الملف الذي نريد قراءته ، وبالنسبة للبساطة ، فهو ملف خصائص.
2. فئة الوصول إلى البيانات: testdao.java
package com.iteye.redhacker.jersey.dao ؛ استيراد java.io.ioException ؛ استيراد java.io.inputstream ؛ استيراد java.net.url ؛ استيراد java.util.properties com.iteye.redhacker.jersey.exception.exceptioncode ؛ componentpublic class testdao {public string salehello () {classloader classloader = testdao.class.getClassLoader () ؛ classloader.getResource (inifile) ؛ inputStream هو ؛ حاول {iS = url.openStream () ؛} catch (ioException e) {throw new daoException (e ، stisplyCode.read_file_failed) ؛} properties forud = null ؛ {if (forp == null) { الخصائص () ؛) استثناء code.colse_file_failed) ؛}}} إرجاع proper.getProperty ("key1") + "،" + proper.getProperty ("key2") ؛}}في هذه الفئة ، يتم تحويل جميع الاستثناءات التي تم فحصها إلى استثناءات غير محددة (استثناءنا المخصص). عند استدعاء طريقة Sayhello () ، حاول ... التقاط ...
3. فئة تنفيذ الأعمال: TestService.java
package com.iteye.redhacker.jersey.service ؛ استيراد org.springframework.beans.factory.annotation.autowired ؛ استيراد org.springframework com.iteye.redhacker.jersey.exception.serviceException ؛ componentpublic class testService {autowiredPrivat testdao.sayhello () ؛}/** * param testdao testdao لتعيين */public void settestdao (testdao testdao) {this.testdao = testdao ؛}}في هذا الفصل ، نلقي استثناء العمل الخاص بنا ، وهو استثناء لم يتم التحقق منه.
ملاحظة: لقد حققنا فئة TestDao باستخدام Autowired ، وهو شرح توضيحي مقدمة من الربيع ؛ يجب أن نقدم طريقة محددة لتعليق السمات ، وإلا سيفشل التعليق التوضيحي.
4. طلب الوصول إلى فئة الوصول: TestResources.java
package com.iteye.redhacker.jersey.delegate ؛ استيراد javax.ws.rs.get ؛ استيراد javax.ws.rs.path ؛ استيراد javax.ws.rs.produces ؛ import javax.ws.rs.queryparam ؛ import javax.ws.rs.core. com.sun.jersey.api.spring.autowire ؛@path ("/test")@autowirepublic class testResources {private testService testService ؛@get@produces (mediaType.text_plain) public sealhello (QereryParam ("n" int n) TestService testService لتعيين */public void settestService (TestService Service) {this.testService = testService ؛}}هنا هو مورد محدده جيرسي. يمكننا الوصول إلى هذا المورد بهذه الطريقة: البدء في طلب الحصول على طلب /موارد /اختبار URI ، وتمرير معلمة استعلام n ، على سبيل المثال: /test؟ n = 1
ملاحظة: استخدمنا Autowire ليس تعليقًا على الربيع ، إنه تعليق توضيحي لحزمة تكامل جيرسي ؛ يجب أن نقدم طريقة محددة لتعليق السمات ، وإلا سيفشل التعليق التوضيحي.
5. فئة معالج الاستثناء الموحدة: استثناء appersupport.java
package com.iteye.redhacker.jersey.jaxrs ؛ استيراد javax.servlet.servletcontext ؛ استيراد javax.servlet.http.httpservletrequest ؛ javax.ws.rs.core.response.status ؛ استيراد javax.ws.rs.ext.exceptionmapper ؛ استيراد javax.ws.res.ext.provider ؛ استيراد org.apache.log4j.logger com.iteye.redhacker.jersey.exception.baseexception ؛ استيراد com.iteye.redhacker.jersey.exception.exceptionCode ؛ استيراد com.sun.jersey.api.notfoundexception ؛/*** interiple stisply handler*/@providerpublic class isplassupport piarements stispionment < logger.getLogger (استثناء appersupport.class) ؛ سلسلة نهائية ثابتة خاصة context_attribute = webapplicationContext.root_web_application_context_attribut استجابة toreSponse (استثناء استثناء) {string message = stiventcode.internal_server_error ؛ status status dode = status.internal_server_error ؛ webapplicationcontext context = (webapplicationContext) servletContext.getAttribute (context_attribute) (baseexception) استثناء ؛ رمز السلسلة = baseexception.getCode () status.not_found ؛} // يتم تسجيل الاستثناء المحدد والاستثناءات غير المحددة في logger.error (رسالة ، استثناء) ؛ Return Response.ok (Message ، MediaType.text_plain) .status (statusCode) .build () ؛}}في هذه الفئة ، نتعامل مع الاستثناء غير المحدد الذي حددناه ، وكذلك التعامل مع استثناءات غير معروفة للنظام (بما في ذلك استثناءات غير معروفة غير محددة واستثناءات محددة). طريقة المعالجة الخاصة بنا هي: سجل سجل الاستثناء ؛ ب. إرسال رمز حالة الخطأ القياسي القياسي HTTP ورسالة الخطأ إلى العميل ، ويتعامل العميل مع معلومات الخطأ بنفسه. تجدر الإشارة إلى أن طريقة المعالجة هذه تتم دعوتها بواسطة REST ، وتستخدم بشكل مناسب رمز الحالة القياسي HTTP ؛
في هذه الفئة ، نستخدم أيضًا مكون التكوين الدولي لـ Spring لتدويل مفتاح الخطأ الذي ألقاه النظام ، والذي يفضي إلى ترقية تدويل مشروعنا.
6. فئة قاعدة الاستثناء المخصصة: baseexception.java
Package com.iteye.redhacker.jersey.exception ؛/*** فئة قاعدة الاستثناء ، يتم موروثة استثناءات وقت التشغيل لكل وحدة من هذه الفئة*/public class baseexception يمتد RunTimeException {/*** SerialVersionuid*/private static statialversionuid = 1381325479896057076Ll ؛ / ** * مفتاح الرسالة */ رمز السلسلة الخاص ؛ / ** * params message */ private object [] القيم ؛ / ** * regurn الكود */ السلسلة العامة getCode () {return code ؛ } / ** * param code الكود لتعيين * / public void setCode (رمز السلسلة) {this.code = code ؛ } / *** regurn القيم* / الكائن العام [] getValues () {return stable ؛ } / ** * param القيم القيم لتعيين * / public void setValues (object [] القيم) {this.values = القيم ؛ } public baseexception (رسالة السلسلة ، السبب القابل للتسمية ، رمز السلسلة ، الكائن [] القيم) {super (message ، cause) ؛ this.code = رمز ؛ this.values = القيم ؛ }}تحدد هذه الفئة القالب الأساسي لفئة استثناء المشروع ، والاستثناءات الأخرى التي ترث منها. تجدر الإشارة إلى أنها تستخدم بذكاء بعض ميزات التكوين الدولي ويمكنها حتى رمي رسالة خطأ محددة أدناه ، وإعادة استخدام رسالة الخطأ عن طريق تمرير المعلمات:
{0} {1} خطأ المعلمة
7. استثناءات أخرى هي نفسها في الأساس ، ولكن الأنواع مختلفة. دعونا نلقي نظرة على daoException.java
package com.iteye.redhacker.jersey.Exception ؛ الفئة العامة daoException يمتد baseexception {/** * Constructors * * @param code */public daoException (code string) {super (code ، null ، code) ؛ {super (رمز ، السبب ، رمز ، فارغ) ؛}/** * * * * param رمز * رمز الخطأ * قيم param * مجموعة من معلومات الاستثناء المعلقة المعلقة */public daoException (رمز السلسلة ، الكائن [] قيم) {super (رمز ، رمز ، القيم) ؛ المعلمات */public daoException (السبب القابل للتسمية ، رمز السلسلة ، الكائن [] القيم) {super (رمز ، خالية ، رمز ، قيم) ؛} serialversionuid النهائي الثابتة الخاصة = -371129061397333714L ؛}يرث baseexception. عندما يتم طرح هذا الاستثناء ، نصدر أحكام أولية مباشرة من اسم الاستثناء ، ويأتي الخطأ من طبقة DAO.
8. errmsg.properties يستخدم لتحديد معلومات الاستثناء. لنلقي نظرة:
read.file.failed = read file فشل read.config.failed = فشل عنصر التكوين في must.be.bely.than.10 = يجب أن تكون المعلمة أقل من 10colse.file.failed = refile file request.not.found = الخدمة المقابلة لم يتم العثور عليها.
ثالثا. النشر والاختبار
يمكنك تنزيل الكود المصدري في مرفق هذه المقالة. بعد استيراد Eclipse ، تحقق من رمز المصدر.
النشر بسيط للغاية ، فقط أضف tomcat/config/server.xml:
<sost> ... <context path = "/a" reloadable = "true" docbase = "d:/workspace/test/jerseyexceptionmappertest/web"/> </soved>
فقط ابدأ Tomcat!
قم بإجراء اختبارين:
1.
2.
للاختبار الأول ، يمكنك أيضًا رؤية خطأ الاستثناء التالي في السجل:
[2013-08-15 00:25:55] [خطأ] يجب أن تكون المعلمة أقل من 10com.iteye.redhacker.jersey.exception.serviceexception: must.be.less.than.10at com.iteye.redhacker.jersey.service.testservice.sayhello (testsservice.java.java.20) com.iteye.redhacker.jersey.delegate.testresources.sayhello (testresources.java:21) في sun.reflect.nativemethodaccessoriMpl.invoke0 (الطريقة الأصلية) في sun.reflect.nativemetaccessorimpl.invoke Sun.Reflect.DelegatingMethodAccessorImpl.Invoke (DevatingMethodAccessorImpl.java:25) في java.lang.reflect.method.invoke (method.java:597) في com.sun.jersey.spi.container.javamethodinvokerfactory $ 1.invoke (javamethodinvokerfactory.java:60) في com.sun.jersey.spi.container.javamethodinvokerfactory $ 1.invoke com.sun.jersey.server.impl.model.method.dispatch.abstresourcemethoddispatchprovider $ typeoutinvoker._dispatch (Abstractresourcemethoddispatchprovider.java:185) في com.sun.jersey.server.impl.model.method.dispatch.resourcejavamethoddispatcher.dispatch (ResourceJavamethoddispatcher.java:75) في com.sun.jersey.server.impl.uri.rules.htpmmethodrule.javacett في com.sun.jersey.server.impl.uri.rules.resourceclassrule.accept (ResourceClassrule.java:108) في com.sun.jersey.server.impl.uri.rules.righthandpathrule.accept com.sun.jersey.server.impl.uri.rules.RootResourCeClassesRule.accept (RootResourClassesRule.java:84) في com.sun.jersey.server.impl.application.webapplicationImpl._handlerequest com.sun.jersey.server.impl.application.webapplicationImpl._handlerequest (webapplicationImpl.java:1414) على com.sun.jersey.server.impl.application.webapplicpl. com.sun.jersey.server.impl.application.webapplicationImpl.HandLeRequest (WebApplicationImpl.java:1353)
بالنسبة للاختبارات الأخرى ، يمكنك تجربتها ، مثل حذف test.properties عن عمد. عندما لا يمكن العثور على الملف المراد قراءته ، كيف يتم تحويل الاستثناء الذي تم فحصه إلى استثناء غير محدد ذاتيًا ، وتسجيله ، وإرجاع رمز حالة خطأ HTTP القياسي ومعلومات الخطأ إلى العميل.
4. ملخص
1. ليس من الصعب رؤية إطار Jersey في تطوير مشاريع الويب ، لقد تعاملنا مع الاستثناء الذي تم التحقق منه واستثناء غير مرغوب فيه بشكل موحد قدر الإمكان على مستوى الإطار حتى نتمكن من إيلاء المزيد من الاهتمام لتنفيذ الأعمال.
2. إذا كان مشروعًا غير ويب ، أعتقد أنه ينبغي على مصمم هندسة البرنامج أيضًا محاولة التعامل مع الاستثناءات بشكل موحد ؛ إذا لم يتم التعامل معها بشكل موحد ، عند مواجهة استثناء تم فحصه ، فيجب علينا التعامل معه بشكل مناسب ، بدلاً من مجرد القيام بـ E.PrintStackTrace () ؛ إذا لم نتمكن من استرداد الاستثناء ، فيجب علينا على الأقل تسجيل معلومات الخطأ في الاستثناء تمامًا في ملف السجل بحيث يتم التحقق من الأخطاء عند فشل البرامج اللاحقة.
النص الكامل (نهاية)