حساب المجموع الإجمالي لجميع الأرقام في حلقة c:forEach

StackOverflow https://stackoverflow.com/questions/102964

سؤال

لدي حبة جافا مثل هذا:

class Person {
  int age;
  String name;
}

أرغب في التكرار على مجموعة من هذه الحبوب في ملف JSP، مع عرض كل شخص في صف جدول HTML، وفي الصف الأخير من الجدول أود عرض إجمالي جميع الأعمار.

سيبدو رمز إنشاء صفوف الجدول كما يلي:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>

ومع ذلك، أجد صعوبة في إيجاد طريقة لحساب إجمالي العمر الذي سيتم عرضه في الصف الأخير دون اللجوء إلى التعليمات البرمجية النصية, ، أي اقتراحات؟

هل كانت مفيدة؟

المحلول

ملحوظة: حاولت الجمع بين الإجابات لإنشاء قائمة شاملة.لقد ذكرت الأسماء حيثما يكون ذلك مناسبًا لمنح الائتمان عند استحقاقه.

هناك العديد من الطرق لحل هذه المشكلة، ولكل منها إيجابيات وسلبيات:

حل JSP النقي

كما ذكر ScArcher2 أعلاه، فإن الحل السهل والبسيط للغاية لهذه المشكلة هو تنفيذه مباشرة في JSP كما يلي:

<c:set var="ageTotal" value="${0}" />
<c:forEach var="person" items="${personList}">
  <c:set var="ageTotal" value="${ageTotal + person.age}" />
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
${ageTotal}

المشكلة في هذا الحل هي أن JSP يصبح مربكًا لدرجة أنه من المحتمل أن تكون قد أدخلت نصوصًا برمجية.إذا كنت تتوقع أن كل من ينظر إلى الصفحة سيكون قادرًا على اتباع المنطق البدائي الموجود، فهذا اختيار جيد.

حل EL النقي

إذا كنت تستخدم بالفعل EL 3.0 (Java EE 7 / Servlet 3.1)، فاستخدم الدعم الجديد لـ تيارات ولامدا:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
${personList.stream().map(person -> person.age).sum()}

وظائف JSP EL

هناك طريقة أخرى لإخراج الإجمالي دون إدخال كود البرنامج النصي في JSP الخاص بك وهي استخدام وظيفة EL.تتيح لك وظائف EL استدعاء طريقة ثابتة عامة في فئة عامة.على سبيل المثال، إذا كنت ترغب في التكرار على مجموعتك وجمع القيم، فيمكنك تحديد طريقة ثابتة عامة تسمى sum(List people) في فئة عامة، ربما تسمى PersonUtils.في ملف tld الخاص بك، ستضع الإعلان التالي:

<function>
  <name>sum</name>
  <function-class>com.example.PersonUtils</function-class>
  <function-signature>int sum(java.util.List people)</function-signature>
</function> 

داخل JSP الخاص بك سوف تكتب:

<%@ taglib prefix="f" uri="/your-tld-uri"%>
...
<c:out value="${f:sum(personList)}"/>

تتمتع وظائف JSP EL ببعض الفوائد.إنها تسمح لك باستخدام أساليب Java الحالية دون الحاجة إلى ترميز واجهة مستخدم محددة (مكتبات العلامات المخصصة).كما أنها مدمجة ولن تربك أي شخص غير برمجي.

علامة مخصصة

هناك خيار آخر يتمثل في إنشاء علامتك المخصصة.سيتضمن هذا الخيار معظم عمليات الإعداد ولكنه سيمنحك ما أعتقد أنك تبحث عنه بشكل أساسي، بدون أي نصوص برمجية على الإطلاق.يمكن العثور على برنامج تعليمي لطيف لاستخدام العلامات المخصصة البسيطة على http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags5.html#74701

تتضمن الخطوات المتبعة تصنيفًا فرعيًا لـ TagSupport:

public PersonSumTag extends TagSupport {

   private List personList;

   public List getPersonList(){
      return personList;
   }

   public void setPersonList(List personList){
      this.personList = personList;
   }

   public int doStartTag() throws JspException {
      try {
        int sum = 0;
        for(Iterator it = personList.iterator(); it.hasNext()){
          Person p = (Person)it.next();
          sum+=p.getAge();
        } 
        pageContext.getOut().print(""+sum);
      } catch (Exception ex) {
         throw new JspTagException("SimpleTag: " + 
            ex.getMessage());
      }
      return SKIP_BODY;
   }
   public int doEndTag() {
      return EVAL_PAGE;
   }
}

تحديد العلامة في ملف tld:

<tag>
   <name>personSum</name>
   <tag-class>example.PersonSumTag</tag-class>
   <body-content>empty</body-content>
   ...
   <attribute>
      <name>personList</name>
      <required>true</required>
      <rtexprvalue>true</rtexprvalue>
      <type>java.util.List</type>
   </attribute>
   ...
</tag>

قم بتعريف taglib أعلى JSP الخاص بك:

<%@ taglib uri="/you-taglib-uri" prefix="p" %>

واستخدم العلامة:

<c:forEach var="person" items="${personList}">
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
<p:personSum personList="${personList}"/>

عرض العلامة

كما ذكر zmf سابقًا، يمكنك أيضًا استخدام علامة العرض، على الرغم من أنك ستحتاج إلى تضمين المكتبات المناسبة:

http://displaytag.sourceforge.net/11/tut_basic.html

نصائح أخرى

هل تحاول جمع كل الأعمار؟

يمكنك حسابها في وحدة التحكم الخاصة بك وعرض النتيجة فقط في ملف jsp.

يمكنك كتابة علامة مخصصة لإجراء الحساب.

يمكنك حسابها في jsp باستخدام jstl مثل هذا.

<c:set var="ageTotal" value="${0}" />
<c:forEach var="person" items="${personList}">
  <c:set var="ageTotal" value="${ageTotal + person.age}" />
  <tr><td>${person.name}<td><td>${person.age}</td></tr>
</c:forEach>
${ageTotal}

تحقق من علامة العرض. http://displaytag.sourceforge.net/11/tut_basic.html

ScArcher2 لديه أبسط حل.إذا كنت تريد شيئًا مضغوطًا قدر الإمكان، فيمكنك إنشاء مكتبة علامات تحتوي على وظيفة "sum" بداخلها.شيء مثل:

class MySum {
public double sum(List list) {...}
}

في نطاق المستوى الأعلى الخاص بك:

<function>
<name>sum</name>
<function-class>my.MySum</function-class>
<function-signature>double sum(List)</function-signature>
</function>

في JSP الخاص بك، سيكون لديك شيء مثل:

<%@ taglib uri="/myfunc" prefix="f" %>

${f:sum(personList)}

إنه أمر مبتكر بعض الشيء، ولكن في كود وحدة التحكم الخاصة بك، يمكنك فقط إنشاء كائن شخص وهمي يحتوي على الإجمالي!

كيف يمكنك استرجاع الأشياء الخاصة بك؟يتيح لك HTML تعيين <تفوت> العنصر الذي سيكون موجودًا أسفل أي بيانات لديك، وبالتالي يمكنك فقط تعيين الإجمالي بشكل منفصل عن كائنات الشخص وإخراجه على الصفحة كما هو دون أي حساب على صفحة JSP.

يمكنك التكرار على مجموعة باستخدام JSTL وفقًا لما يلي

<c:forEach items="${numList}" var="item">
      ${item}
</c:forEach>

إذا كانت خريطة يمكنك القيام بها على ما يلي

<c:forEach items="${numMap}" var="entry">
  ${entry.key},${entry.value}<br/>
</c:forEach>

يعد حساب الإجماليات/ أو الملخصات الأخرى في وحدة التحكم - وليس في JSP - أمرًا مفضلاً بشدة.

استخدم كود Java ونهج MVC، على سبيل المثال إطار عمل Spring MVC، بدلاً من محاولة القيام بالكثير في JSP أو JSTL؛يعد إجراء عمليات حسابية مهمة بهذه اللغات أمرًا ضعيفًا وبطيئًا، ويجعل صفحات JSP الخاصة بك أقل وضوحًا.

مثال:

class PersonList_Controller implements Controller {
    ...
    protected void renderModel (List<Person> items, Map model) {
        int totalAge = 0;
        for (Person person : items) {
            totalAge += person.getAge();
        }
        model.put("items", items);
        model.put("totalAge", totalAge);
    }
}

من حيث اتخاذ القرار بشأن التصميم - في أي مكان مطلوب فيه إجمالي، يمكن تمديده في الشهر المقبل ليتطلب متوسطًا ووسيطًا وانحرافًا معياريًا.

نادرًا ما تتماسك حسابات وتلخيصات JSTL معًا، في مجرد الحصول على المجموع.هل تريد حقًا تلبية أي متطلبات موجزة أخرى في JSTL؟أعتقد أن الإجابة هي لا - وبالتالي فإن قرار التصميم الصحيح هو حسابه في وحدة التحكم، على قدم المساواة/أكثر بساطة وبالتأكيد أكثر معقولية - المتطلبات القابلة للتوسيع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top