2015-03-11 13 views
5

Scenariusz:JasperReport: Jak używać wartości zwracanych Podraport jako wejście na główny Zgłoś Variable Kalkulacja

mam dwa raporty: raportu głównego (nazwijmy go A) i Podraport (nazwijmy to, B).

Raport A zawiera pod-raport B w paśmie szczegółów, więc pod-raport B jest wyświetlany dla każdego elementu w źródle danych raportu. Podraport B również zwraca zmienną do głównego raportu A.

Chcę, aby podsumował wartości zwracane z podpodpisu B i zsumował je w podsumowaniu raportu głównego.

Aby to zrobić, próbowałem utworzyć nowy raport zmiennej tej sumy tych wartości Zwraca ... coś takiego:

Variable Definition Example

jednak odkryłem, że wyrażenie takie zmienne są zawsze obliczane przed renderowaniem szczegółów pasma, więc zawsze brakuje mi pierwszej wartości zwracanej w raporcie podrzędnym ...

Niestety, czas oceny (jak to link mówi) nie może być zmieniony dla tego rodzaju zmiennych, więc jestem utknął ...

+0

Mam ten sam problem z tym, że tęsknię nie tylko pierwszy sub-raportu wartości zwracanej. – Gustavo

Odpowiedz

2

Po tym, jak borykałem się z tym przez kilka godzin ... i szukałem rozwiązania w Internecie ... Przyjąłem rozwiązanie (fora oświecające były następujące: one i two).

Najpierw należy zdefiniować klasę pomocnika języka Java, która pozwala obliczyć operację arytmetyczną, w moim przypadku operację Sum. I zdefiniowano następujące klasy:

package reports.utils; 
 

 
import java.util.Map; 
 

 
/** 
 
* Utility that allows you to sum Integer values. 
 
*/ 
 
public class SumCalculator { 
 

 
    /** 
 
    * Stores a map of {@code SumCalculator} instances (A Map instance per thread). 
 
    */ 
 
    private static final ThreadLocalMap<String, SumCalculator> calculatorsIndex = new ThreadLocalMap<>(); 
 

 
    /** 
 
    * The sum total. 
 
    */ 
 
    private int total = 0; 
 

 

 
    /** 
 
    * No arguments class constructor. 
 
    */ 
 
    private SumCalculator() { 
 
     super(); 
 
    } 
 

 

 
    /** 
 
    * Instance a new {@code SumCalculator} with the given ID. 
 
    * 
 
    * @param id {@code SumCalculator}'s ID 
 
    * @return  the new {@code SumCalculator} instance 
 
    */ 
 
    public static SumCalculator get(String id) { 
 
     Map<String, SumCalculator> map = calculatorsIndex.get(); 
 
     SumCalculator calculator  = map.get(id); 
 

 
     if (calculator == null) { 
 
      calculator = new SumCalculator(); 
 
      map.put(id, calculator); 
 
     } 
 
     return calculator; 
 
    } 
 

 

 
    /** 
 
    * Destroy the {@code SumCalculator} associated to the given ID. 
 
    * 
 
    * @param id {@code SumCalculator}'s ID 
 
    * @return  {@code null} 
 
    */ 
 
    public static String destroy(String id) { 
 
     Map<String, SumCalculator> map; 
 

 
     map = calculatorsIndex.get(); 
 
     map.remove(id); 
 

 
     if (map.isEmpty()) { 
 
      calculatorsIndex.remove(); 
 
     } 
 
     return null; 
 
    } 
 

 

 
    /** 
 
    * Resets the {@code SumCalculator} total. 
 
    * 
 
    * @return {@code null} 
 
    */ 
 
    public String reset() { 
 
     total = 0; 
 
     return null; 
 
    } 
 

 

 
    /** 
 
    * Adds the given integer value to the accumulated total. 
 
    * 
 
    * @param i  an integer value (can be null) 
 
    * @return  {@code null} 
 
    */ 
 
    public String add(Integer i) { 
 
     this.total += (i != null) ? i.intValue() : 0; 
 
     return null; 
 
    } 
 

 

 
    /** 
 
    * Return the accumulated total. 
 
    * 
 
    * @return an Integer value (won't be null, never!) 
 
    */ 
 
    public Integer getTotal() { 
 
     return this.total; 
 
    } 
 
}

package reports.utils; 
 

 
import java.util.HashMap; 
 
import java.util.Map; 
 

 
/** 
 
* Thread Local variable that holds a {@code java.util.Map}. 
 
*/ 
 
class ThreadLocalMap<K, V> extends ThreadLocal<Map<K, V>> { 
 

 
    /** 
 
    * Class Constructor. 
 
    */ 
 
    public ThreadLocalMap() { 
 
     super(); 
 
    } 
 

 

 
    /* (non-Javadoc) 
 
    * @see java.lang.ThreadLocal#initialValue() 
 
    */ 
 
    @Override 
 
    protected Map<K, V> initialValue() { 
 
     return new HashMap<>(); 
 
    } 
 
}

drugie, w raporcie jaspisu, trzeba zdefiniować cztery pola tekstowe:

1) tekst dziedzinie, która iniatializes swój kalkulator; powinno to być (najlepiej) w sekcji tytułowej raportu i powinno mieć takie wyrażenie: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").reset(). To pole tekstowe powinno mieć czas oceny: TERAZ.

2) Pole tekstowe, które wywołuje funkcję przyrostu (tj SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").add($V{SUB_REPORT_RETURN_VALUE}) To pole tekstowe będzie przebywać w swoim szczegół zespołu, po elementu podraportu, a powinien mieć czas oceny:. BAND (jest to bardzo ważne !!)

3) Pole tekstowe, które drukuje sumę kalkulatorów. To pole tekstowe będzie znajdować się w Twoim podsumowaniu, będzie oceniane na TERAZ. Jego wyrazem będzie: SumCalculator.get("$V{SUB_REPORT_RETURN_VALUE}").getTotal()

4) Pole tekstowe, które niszczy kalkulator. To pole tekstowe będzie również znajdować się w twoim podsumowaniu i musi pojawić się po polu tekstowym 3. Pole tekstowe powinno mieć wyrażenie takie jak: SumCalculator.destroy("$V{SUB_REPORT_RETURN_VALUE}").To pole tekstowe powinno mieć czas oceny: TERAZ.

Również pola tekstowe: 1, 2 i 4 powinny mieć atrybut "Pusty, gdy wartość Null", więc nigdy nie będą drukowane (dlatego te operacje java zawsze zwracają wartość null).

I to wszystko. Następnie raport może wyglądać następująco:

reportExample

+0

Zbyt skomplikowane. Jeśli istnieje coś takiego jak "reset" typu pasma dla zmiennej ... – Gustavo

+0

Nie jestem ekspertem, ale rozumiem, że takie resetowanie działa tylko z wyrażeniem zmiennych (które nie może pokryć mojego wymogu) –

+0

Mam na myśli rodzaj przyrostu, nie resetuj typ. Przepraszam. Inkrementem jest moment, w którym można uzyskać wartość z wyrażenia ($ V {SUB_REPORT_RETURN_VALUE}). – Gustavo

0

jeśli mogę zrozumieć problem, nie można podsumować kwoty zwróconej przez raporcie sub w raporcie głównym, miałem ten sam problem i rozwiązać w tą drogą.

1.- Utwórz klasę, która rozciąga się od net.sf.jasperreports.engine.JRDefaultScriptlet. i zastąpić metodę beforeReportInit()

to jest kod z tej klasy.

package com.mem.utils; 

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 

import net.sf.jasperreports.engine.JRDefaultScriptlet; 

public class SumarizacionSubtotales extends JRDefaultScriptlet { 
    private final Log log = LogFactory.getLog(getClass()); 

    private Double total; 

    public Double getTotal() { 
     return total; 
    } 

    public Double add(Double cantidad) { 
     if(log.isDebugEnabled())log.debug("AGREGANDO LA CANTIDAD : " + cantidad); 
     this.total += cantidad; 
     return cantidad; 
    } 
    @Override 
    public void beforeReportInit() throws JRScriptletException { 
     if(log.isDebugEnabled())log.debug("beforeReportInit"); 
     total = 0.0D; 
    } 
} 

2.- dodaj słoik projektu w swojej ścieżce Classpath. ireport classpath config.

3.- Zastąp klasę skryptletu RAPORT. default REPORT scriptlet

we właściwościach Twojej klasy. your class

3.- dodać stopkę grupy, w której chcesz wydrukować wartość zwróconą przez podraport, pole tekstowe z następującym wyrażeniem.

$P{REPORT_SCRIPTLET}.add($V{sum_detalles}) 

W tym przypadku $ {V} sum_detalles jest zmienną w raporcie głównym, który zawiera wartość zwracaną przez sub-raportu.

4.- Dodaj na stronie Last stopka innego pola tekstowego z następującym wyrażeniem.

$P{REPORT_SCRIPTLET}.getTotal() 

report structure

+0

Moim prawdziwym problemem był czas oceny wyrażenia, który oblicza zmienną dla raportu globalnego (został obliczony przed każdym szczegółem pasma, więc zawsze brakuje mi wartości zwracanej pierwszego podraportu) ... Wygląda na to, że (zgodnie z twoim przykład) scriptlet Klasa jest oceniana po renderowaniu każdego szczegółu pasma ... –

+0

Jeśli widzisz kod dodałem metodę ** beforeReportInit() ** w klasie, to pozwala na zainicjalizowanie zmiennej, pracowałem dobrze dla mnie . – OJVM

Powiązane problemy