<bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"><value>doIt</value></property>
</bean>
The above example will result in the doIt being called on the exampleBusinessObject (see below):
public class BusinessObject {
// properties and collaborators
public void doIt() {
// do the actual work
}
}
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>
Using the MethodInvokingJobDetailFactoryBean you don't need to create one-line jobs that just invoke a method, and you only need to create the actual business object and wire up the detail object.
使用MethodInvokingJobDetailFactoryBean ä½ ä¸éœ€è¦åˆ›å»ÞZ¸€ä¸ªåœ¨¾U¿çš„jobsåQŒä»…ä»…è°ƒç”¨å®ƒçš„æ–¹æ³•ï¼Œä½ å¯ä»¥ä»…ä»…åªéœ€è¦åˆ›å»ÞZ¸€ä¸ªå®žé™…的逻辑对象òq¶ä¸”把它¾l‘定到细节对象ã€?/P>
By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail objects implement the Stateful interface, this won't happen. The second job will not start before the first one has finished. To make jobs resulting from the MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.
¾~ºçœåœŽÍ¼ŒQuartz jobsæ˜¯æ— çŠ¶æ€çš„åQŒåœ¨jobsçš„å¯èƒ½æ€§ä½œä¸ºç»“果媄å“å½¼æ¤ã€‚å¦‚æžœä½ é™å®šä¸¤ä¸ªè§¦å‘噍䨓åŒä¸€ä¸ªJohDetail,它在½W¬ä¸€ä¸ªjobå·²ç»å®Œæˆæ—¶æ˜¯å¯èƒ½çš„,½W¬äºŒä¸ªå°†ä¼šå¼€å§‹ã€‚如果JobDetailå®žçŽ°äº†çŠ¶æ€æŽ¥å£ï¼Œå®ƒå°†ä¸ä¼šå‘生ã€?BR><bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="exampleBusinessObject"/></property>
<property name="targetMethod"><value>doIt</value></property>
<property name="concurrent"><value>false</value></property>
</bean>
Note: By default, jobs will run in a concurrent fashion.
<bean id="methodInvokingJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="financeDAO"/></property>
<property name="targetMethod"><value>confirmOrder</value></property>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="methodInvokingJobDetail"/>
</property>
<property name="cronExpression">
<value>0 0 6,12,20 * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list><ref local="cronTrigger"/></list>
</property>
</bean>
上题q™æ®µé…置文äšg规定了在早上6点和晚上8ç‚ÒŽ‰§è¡ŒfinanceDAO对象的confirmOrder()æ–ÒŽ³•.
附:cronExpressioné…置说明
å—æ®µ | å…许å€?/TH> | å…许的特ŒDŠå—½W?/TH> | ||
---|---|---|---|---|
¿U?/CODE> |
0-59 |
, - * / | ||
�/CODE> |
0-59 |
, - * / | ||
ž®æ—¶ |
0-23 |
, - * / | ||
日期 |
1-31 |
, - * ? / L W C | ||
月䆾 |
1-12 或�JAN-DEC |
, - * / | ||
星期 |
1-7 或�SUN-SAT |
, - * ? / L C # | ||
òqß_¼ˆå¯é€‰ï¼‰ |
留空, 1970-2099 |
, - * / |
Trigger-related events include: trigger firings,trigger mis-firings(discussed in the "Triggers" sections of this document),and trigger completions (the jobs fired off by the trigger is finished).
To create a listener,simply create an object the implements either the org.quartz.TriggerListener and/or org.quartz.JobListener interface. Listeners are then registered with the scheduler during run time ,and must be given a name(or rather ,they must advertise their own name via their getName()method. Listeners can be registered as either "global" or "non-global". Global listeners receive events for ALL triggers/jobs, and non-global listeners receive events only for the specific triggers/jobs that explicitely name the listener in their getTriggerListenerNames() or getJobListenerNames() properties.
scheduler.addGlobalJobListener(myJobListener);
or
scheudler.addJobListener(myJobListener);
Listeners are not used by most users of Quartz,but are handy when application requirements create the need for the notification of events,without the Job itself explicitly nofifying the application.
CronTriggers are often more useful than SimpleTrigger, if you need a job-firing schedule that recurs based on calendar-like notions, rather than on the exactly specified intervals of SimpleTrigger.
CronTriggers 比SimpleTrigger¾lå¸¸æ›´åŠ æœ‰ç”¨,å¦‚æžœä½ éœ€è¦ä¸€ä¸ªåŸºäºŽåƒæ—¥åŽ†æ¦‚å¿µçš„é‡å¤?job-firing 调度åQŒè€Œä¸æ˜¯åœ¨ä¸€ä¸ªSimpleTrigger特定的间隔ã€?/P>
With CronTrigger, you can specify firing-schedules such as "every Friday at noon", or "every weekday and 9:30 am", or even "every 5 minutes between 9:00 am and 10:00 am on every Monday, Wednesday and Friday".
使用CronTrigger,ä½ å¯ä»¥é™å®šfiring-schedulers例如 “æ¯å¤©ä¸åˆâ€œï¼Œæˆ–者â€ï¼Œâ€æ¯å¤©å‘¨æ—¥ä¸Šå?:30“,或者甚è‡?“æ¯5分钟在上å?åQ?0 åˆ?10åQ?0 æ¯å‘¨ä¸€ã€å‘¨ä¸‰ã€å‘¨äº”â€?/P>
Cron Expressions
Cron 表达�/P>
Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up of six sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:
Cron 表达å¼è¢«ç”¨æ¥æ³¨å†ŒCronTrigger实例的。Cronè¡¨è¾¾å¼æ˜¯å—符ä¸ÔŒ¼Œå®ƒç”±å…个å表辑ּ¾l„æˆåQŒå®ƒæè¿°äº†ä¸åŒçš„调度¾l†èŠ‚ã€‚è¿™äº›å表达å¼è¢«ç™½è‰²è¡¨è¾¾å¼éš”å¼€åQŒè¡¨çŽŽÍ¼š
Seconds ¿U?BR>Minutes åˆ?BR>Hours æ—?BR>Day-of-Month æ—?BR>Month æœ?BR>Day-of-Week å‘?/P>
An example of a complete cron-expression is the string "0 0 12 ? * WED" - which means "every Wednesday at 12:00 pm".
一个完整的Cron 表达å¼ä¾‹å是å—符东y€? 0 12 ? * WEBâ€?æ„å‘³ç€æ¯å‘¨ä¸‰ä¸Šå?2åQ?0ã€?/P>
Individual sub-expressions can contain ranges and/or lists. For example, the day of week field in the previous (which reads "WED") example could be replaces with "MON-FRI", "MON, WED, FRI", or even "MON-WED,SAT".
å•独的å表达å¼å¯ä»¥åŒ…å«åã^行的 å’?或。例如,在上一个例å一周的一天嗌Dµï¼ˆå®ƒè¯»ä½?WED"åQ‰å¯ä»¥è¢«â€œMON-FRIâ€?"MON,WED,FRI"åQŒæˆ–者甚è‡?MON-WED,SAT"æ›¿æ¢æŽ‰ã€?/P>
Wild-cards (the '*' character) can be used to say "every" possible value of this field. Therefore the '*' character in the "Month" field of the previous example simply means "every month". A '*' in the Day-Of-Week field would obviously mean "every day of the week".
¾lŸé…½W¦ï¼ˆ"*"å—符åQ‰å¯ä»¥è¢«ç”¨æ¥ä½œäØ“˜q™ä¸ªå—段çš?æ¯ä¸€ä¸?å¯èƒ½å€¹{€‚所ä»?åœ¨ä¸Šä¸€ä¸ªä¾‹åæœˆå—段ä¸çš„"*"å—符表示æ¯ä¸ªæœˆã€?一ä¸?*"在周天将明显æ„味ç€å‘¨çš„æ¯ä¸€å¤©ã€?/P>
All of the fields have a set of valid values that can be specified. These values should be fairly obvious - such as the numbers 0 to 59 for seconds and minutes, and the values 0 to 23 for hours. Day-of-Month can be any value 0-31, but you need to be careful about how many days are in a given month! Months can be specified as values between 0 and 11, or by using the strings JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC. Days-of-Week can be specified as vaules between 1 and 7 (1 = Sunday) or by using the strings SUN, MON, TUE, WED, THU, FRI and SAT.
所有嗌Dµéƒ½ç”¨ä¸€ä¸ªåˆæ³•é™å®šçš„倹{€‚这些值应该是明显的,例如0åˆ?9æ•°å—为秒和分的é™å®šï¼Œ0åˆ?3ä¸ºå°æ—¶ã€‚月的æŸå¤©å¯ä»¥æ˜¯0-31çš„ï¼Œæˆ–è€…ä½ éœ€è¦æ¶ˆæ¯ç»™ä¸ªæœˆæœ‰å¤šž®‘天åQ月份å¯ä»¥è¢«é™å®šåœ?åˆ?1åQŒæˆ–者,使用英文å—符串羃写。一个礼拜的一天å¯ä»¥è¢«é™å®šä½œäØ“1åˆ?åQ?=SunndayåQ‰æˆ–者ä‹É用英文嗽W¦ä¸²ã€?/P>
The '/' character can be used to specify increments to values. For example, if you put '0/15' in the Minutes field, it means 'every 15 minutes, starting at minute zero'. If you used '3/20' in the Minutes field, it would mean 'every 20 minutes during the hour, starting at minute three' - or in other words it is the same as specifying '3,23,43' in the Minutes field.
"/"å—符å¯ä»¥å†…用æ¥é™å®šå€¼çš„å¢žåŠ ã€‚ä¾‹å¦‚ï¼Œå¦‚æžœä½ å°†'0/15'攑ֈ°åˆ†é’Ÿå—段åQŒå®ƒæ„味ç€"æ¯?5分钟åQŒå¼€å§‹äºŽ0分钟"ã€‚å¦‚æžœä½ ä½¿ç”¨"3/20"在分钟嗌Dµä¸åQŒä½ ž®†æ„味ç€"ä¸€ä¸ªå°æ—¶å†…æ¯?0分钟åQŒå¼€å§‹äºŽ3分钟"--- 或者æ¢a€ä¹‹ï¼Œå®ƒå’Œåœ¨åˆ†é’Ÿå—ŒD?3,23,43"é™å®šæ˜¯ä¸€æ ïLš„ã€?/P>
The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify "no specific value". This is useful when you need to specify something in one of the two fields, but not the other. See the examples below (and CronTrigger JavaDOC) for clarification.
"?"å—符是å…è®æ€Ø“月的æŸä¸€å¤©æˆ–者周的æŸä¸€å¤©å—ŒD늚„。它被用æ¥é™å®?没有é™å®šå€?。这是有用的åQŒå½“ä½ éœ€è¦é™å®šä¸€äº›äº‹æƒ…åœ¨ä¸€ä¸ªæˆ–ä¸¤ä¸ªå—æ®µä¸ï¼Œä½†ä¸æ˜¯è¿™é‡Œçš„ã€?/P>
The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" or "FRIL" both mean "the last friday of the month". When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing results.
"L"å—符是å…è®¸ç”¨æ¥æœˆæŸå¤©å’Œå‘¨æŸå¤©å—段。这个嗽W¦æ˜¯ä¸€ä¸?last"的羃写,但是它有ä¸åŒçš„æ„ä¹‰åœ¨ä¸¤ä¸ªå—æ®µçš„å…¶ä¸ä¹‹ä¸€ã€‚例如,˜q™ä¸ªå€?L"åœ¨æœˆå—æ®µçš„æŸä¸€å¤©æ„味ç€" ˜q™ä¸ªæœˆçš„æœ€åŽä¸€å¤?åQ?1或è€?8½{‰ç‰ã€?/P>
Here are a few more examples of expressions and their meanings - you can find even more in the JavaDOC for CronTrigger
CronTrigger Example 1 - an expression to create a trigger that simply fires every 5 minutes
"0 0/5 * * * ?"
CronTrigger Example 2 - an expression to create a trigger that fires every 5 minutes, at 10 seconds after the minute (i.e. 10:00:10 am, 10:05:10 am, etc.).
"10 0/5 * * * ?"
CronTrigger Example 3 - an expression to create a trigger that fires at 10:30, 11:30, 12:30, and 13:30, on every Wednesday and Friday.
"0 30 10-13 ? * WED,FRI"
CronTrigger Example 4 - an expression to create a trigger that fires every half hour between the hours of 8 am and 10 am on the 5th and 20th of every month. Note that the trigger will NOT fire at 10:00 am, just at 8:00, 8:30, 9:00 and 9:30
"0 0/30 8-9 5,20 * ?"
Note that some scheduling requirements are too complicated to express with a single trigger - such as "every 5 minutes between 9:00 am and 10:00 am, and every 20 minutes between 1:00 pm and 10:00 pm". The solution in this scenario is to simply create two triggers, and register both of them to run the same job.
Quartz 是一个功能é½å…¨çš„ã€å¼€æºçš„jobæ—‰™—´è°ƒåº¦¾pÈ»ŸåQŒå®ƒå¯ä»¥è¢«ç»“åˆçš„,或者伴éšè™šæ‹Ÿçš„ä»ÖM½•J2EE或J2SE½E‹åº-从最ž®çš„独立的应用程åºåˆ°æœ€å¤§çš„e-commerce¾pÈ»Ÿè¢«ä‹É用。Quartzå¯ä»¥ç”¨æ¥åˆ›å¾½Ž€å•æˆ–å¤æ‚çš„æ—¶é—´è°ƒåº¦æ¥æ‰§è¡Œåã€ç™¾ã€åƒã€ç”šè‡³ä¸Šä¸‡çš„jobs;获得的jobè¢«å®šä¹‰äØ“ä¸€ä¸ªæ ‡å‡†çš„java¾l„äšg或EJBs. ˜q™ä¸ªQuartz æ—‰™—´è°ƒåº¦åŒ…å«å¾ˆå¤šä¼ä¸š¾cÈš„特å¾åQŒä¾‹å¦‚JTA事务和簇ã€?/P>
The licensing of Quartz versions 1.0 through 1.4.5 is similar to both the BSD and ASF (Apache) public licenses, which means it's free for use, even within commercial products.
Quartz 1.0版本åˆ?.4.5版本的licensing 是类ä¼ég¸ŽBSDå’ŒASF(apache)公共licenses, 它æ„味ç€å¯ä»¥å…费使用åQŒç”šè‡³ä‹É用在商业产å“ä¸ä‹É用ã€?BR>With the upcoming release of version 1.5.0, Quartz is moving to the Apache 2.0 license.
ä¼´éš1.5.0版本的å‘布,Quartzž®†è{¿UÕd‘apache 2.0 çš„license.
What can Quartz do for you? (Quartzå¯ä»¥ä¸ÞZ½ åšä»€ä¹ˆï¼Ÿ)
If your application has tasks that need to occur at given moments in time, or if your system has recurring maintenance jobs then Quartz may be your ideal solution.
å¦‚æžœä½ çš„½E‹åºæœ‰ä¸€äº›è¿™æ ïLš„ä»ÕdŠ¡åQŒå®ƒéœ€è¦åŠæ—¶åœ°å‘生在给定时é—ß_¼Œæˆ–è€…ä½ å¦‚æžœä½ çš„¾pÈ»Ÿæœ‰è¿ž¾l维护jobsåQŒé‚£ä¹ˆQuartzå¯ä»¥æˆäØ“ä½ çš„ç†æƒ³çš„è§£å†Ïx–¹æ¡ˆã€?/P>
Sample uses of job scheduling with Quartz:
Quartz使用jobæ—‰™—´è°ƒåº¦çš„范ä¾?/P>
Driving Workflow: As a new order is initially placed, schedule a Job to fire in exactly 2 hours, that will check the status of that order, and trigger a warning notification if an order confirmation message has not yet been received for the order, as well as changing the order's status to 'awaiting intervention'.
System Maintenance: Schedule a job to dump the contents of a database into an XML file every business day (all weekdays except holidays) at 11:30 PM.
工作‹¹é©±åŠ¨ï¼šä½œäØ“ä¸€ä¸ªæ–°çš„è®¢å•被åˆå§‹åŒ–放¾|®ï¼Œè°ƒåº¦ä¸€ä¸ªjobåŽÕd·¥ä½œåœ¨æ£å¥½ä¸¤ä¸ªž®æ—¶å†…,它将‹‚€æŸ¥è®¢å•的状æ€ï¼Œòq¶ä¸”触å‘一个è¦å‘Šé€šçŸ¥å¦‚果订啼‹®è®¤ä¿¡æ¯æ²¡æœ‰è¢«æŽ¥æ”Óž¼Œåˆæ”¹å˜è®¢å•的状æ€åˆ°"½{‰å¾…òq²æ¶‰"ã€?BR>¾pÈ»Ÿ¾l´æŠ¤åQšè°ƒåº¦ä¸€ä¸ªjobæ¥å°†æ•°æ®åº“è{åŒ–äØ“XMLæ–‡äšg æ¯å•†ä¸šæ—¥æœŸï¼ˆæ‰€æœ‰å‘¨æœ«é™¤äº†èЂ凿—¥åQ‰åœ¨ä¸‹åˆ11åQ?0ã€?/P>
The basic way to create an AOP proxy in Spring to use the org.springframework.aop.framework.ProxyFactoryBean. This gives complete control over the pointcuts an advice that will apply, and theire ordering . However ,there are simpler options that are preferable(æ›´å¯å–çš„ã€æ›´å¥½çš„) if you don't need such control.
Basics
The proxyFactoryBean,like other Spring FactoryBean implementations,introduces a level of indirection(间接). If you define a ProxyFactoryBean with name foo,what objects referencing foo see is not the ProxyFactoryBean instance itself, but an object created by the ProxyFactoryBeans's implementation of the getObject() method. This method will create an AOP proxy wrapping a target object.
One of the most important benefits of using a ProxyFactoryBean or other IoC-aware to create AOP proxies, it that it means that advices and pointcuts can also be managed by IoC. This is a powerful feature , enabling certain approaches that are hard to achieve with other AOP frameworks. For example,an advice may itself reference application objects(besides the target , which should be available in any AOP framework),benefiting from all the pluggability provided by Dependency Injection.
JavaBean properties
Like most FactoryBean implementations provided with Spring, ProxyfactoryBean is itself a JavaBean. It properties are used to:
Specify the target you want to proxy
Specify whether to use CGLIB
Some key properties are inherited from org.springframework.aop.framework.ProxyConfig: the subclass for all AOP proxy factories. These include:
proxyTargetClass: true if we should proxy the target class,rather than its interfaces. If this is true we need to use CGLIB.
optimize: whether to apply aggressive optimization to created proxies. Don't use this setting unless you understand how the relevant(相关� AOP proxy handles optimization. This is currently used only for CGLIB proxies;it has no effect with JDK dynamic proxies(the default).
frozen:whether avice changes should be disallowed once the proxy factory has bean configured. Default is false.
exposeProxy: whether the current proxy should be exposed in a ThreadLocal so that it can be accessed by the target (It's available via the MethodInvocation without the need for a ThreadLocal) If a target needs to obtain the proxy and exposedProxy is true, the target can use the AopContext.currentProxy() method.
aopProxyFactory: the implementation of AopProxyFactory to use. Offers a way of customizing whether to use dynammic proxies,CGLIB or any other proxy strategy. The default implementation will choose dynamic proxies or CGLIB appropriately. There should be need to use this property, it's intended to allow the addition of new proxy types in spring 1.1.
Other properties specific to ProxyFactoryBean include:
.proxyInterfaces: array of String interface names. If this isn't supplied, a CGLIB proxy for the target class will be used.
.interceptorNames:String array of Advisor,interceptor or other advice names to apply.Ordering is sugnicicant. first come,first serve that is. The first interceptor in the list will be the first to be able to interceptor the invocation (of course if it concerns a regular MethodInterceptor or BeforeAdvice. The names are bean names in the current factory , including bean names from ancestor factories. You can't mention bean references here since doing so would result iin the ProxyFactoryBean ignoring the singleton setting of the advise. you can append an iinterceptor name with an asterisk(*). This will result in the application of all advisor beans withe names starting with the part before the asterisk to be applied. An example of using this feature can be found below.
Singleton: whether or not the factory should return a single object, no matter how often the getObject() method is called. Server FactoryBean implementations offer such a method. Default value is true. If you want to use stateful advice --for example ,for stateful mixins-user prototype advices along withe s singleton value of false.
Proxying interfaces
<bean id="personTarget" class="com.mycompany.PersionImpl">
<property name="name"><value>Tony</value></property>
<property name="age"><value>51</value></property>
</bean>
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
<property name="someProperty"><value>Custom string property value</value></property>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInteceptor" ></bean>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterface"><value>com.company.Person</value></property>
<property name="target"><ref local="personTarget"/></property>
<property name="interceptorNames">
<list>
<value>myAdvisor</value>
<value>debugInterceptor</value>
</list>
</property>
</bean>
13.7.1. Dependencies åQˆä¾èµ–)
Your application will need to include the latest release of JasperReports, which at the time of writing was 0.6.1. JasperReports itself depends on the following projects:
BeanShell
Commons BeanUtils
Commons Collections
Commons Digester
Commons Logging
iText
POI
JasperReports also requires a JAXP compliant(适应� XML parser.
13.7.2. ConfigurationåQˆé…¾|®ï¼‰
To configure JasperReports views in your ApplicationContext you have to define a ViewResolver to map view names to the appropriate view class depending on which format you want your report rendered in.
13.7.2.1. Configuring the ViewResolver
Typically, you will use the ResourceBundleViewResolver to map view names to view classes and files in a properties file
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property name="basename">
<value>views</value>
</property>
</bean>
Here we've configured an instance of ResourceBundleViewResolver which will look for view mappings in the resource bundle with base name views. The exact contents of this file is described in the next section.
13.7.2.2. Configuring the Views
Spring contains five different View implementations for JasperReports four of which corresponds to one of the four output formats supported by JasperReports and one that allows for the format to be determined at runtime:
JasperReport View Class
1.JasperReportsView CSV
2.JasperReportsHtmlView HTML
3.JasperReportsPdfView PDF
4.JasperReportsXlsView EXCEL
5.JasperReportsMutiFormatView
Mapping one of these classes to a view name and a report file is simply a matter of adding the appropriate entries into the resource bundle configured in the previous section as shown here:
simpleReport.class=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper
Here you can see that the view with name, simpleReport, is mapped to the JasperReportsPdfView class. This will cause the output of this report to be rendered in PDF format. The url property of the view is set to the location of the underlying report file.
13.7.2.3. About Report Files
JasperReports has two distinct types of report file: the design file, which has a .jrxml extension, and the compiled report file, which has a .jasper extension. Typically, you use the JasperReports Ant task to compile your .jrxml design file into a .jasper file before deploying it into your application. With Spring you can map either of these files to your report file and Spring will take care of compiling the .jrxml file on the fly for you. You should note that after a .jrxml file is compiled by Spring, the compiled report is cached for the life of the application. To make changes to the file you will need to restart your application.
JasperReports拥有两ç§ä¸åŒçš„类型的报表文äšgåQšè®¾è®¡æ–‡ä»Óž¼Œå®ƒæ˜¯ä¸€ä¸ªæ‹¥æœ?jrxml 扩展的文ä»Óž¼Œå’Œç¼–è¯‘å¥½çš„æŠ¥è¡¨æ–‡ä»¶ã€‚ä¸€èˆ¬ï¼Œä½ ä‹É用antä»ÕdŠ¡åœ¨ä½ éƒ¨çÖvåˆîC½ 的程åºä¸ä¹‹å‰æ¥ç¼–è¯‘ä½ çš?jrxml设计报表文äšg。ä‹É用Spring ä½ å¯ä»¥åª„ž®„这些文件ä¸çš„ä“Q一åˆîC½ 的报表文ä»Óž¼ŒSpringž®†ä¼šä¸ÞZ½ 在空闲时照顾¾~–译.jrxmlæ–‡äšgã€?ä½ åº”å½“æ³¨æ„在一ä¸?jrxmlæ–‡äšg被编译之åŽï¼Œ˜q™ä¸ª¾~–译的报表是被缓å˜çš„åœ¨ä½ çš„application生命周期ä¸ã€‚如果这些文件修改了åQŒä½ 需è¦é‡æ–°å¯åŠ¨çš„ä½ çš„½E‹åºã€?/P>
13.7.2.4. Using JasperReportsMultiFormatView 使用JasperReportsMutiFormatView
The JasperReportsMultiFormatView allows for report format to be specified at runtime. The actual rendering of the report is delegated to one of the other JasperReports view classes - the JasperReportsMultiFormatView class simply adds a wrapper layer that allows for the exact implementation to be specified at runtime.
JasperReportsMutilFormatViewå…è®¸ä½ åœ¨˜qè¡Œæ—¶æœŸæŒ‡å®šæŠ¥è¡¨çš„æ ¼å¼ã€‚报表的实际的表现是为委托到JasperReports 视图¾cÈš„ä¸çš„一ä¸?-JasperMutilFormatView¾cÈ®€å•çš„åŠ äº†ä¸€ä¸ªåŒ…è£…å±‚å…许在è¿è¡Œæ—¶æœŸæ£¼‹®çš„实现被指定ã€?/P>
The JasperReportsMultiFormatView class introduces two concepts: the format key and the discriminator key. The JasperReportsMultiFormatView class uses the mapping key to lookup the actual view implementation class and uses the format key to lookup up the mapping key. From a coding perspective you add an entry to your model with the formay key as the key and the mapping key as the value, for example:
public ModelAndView handleSimpleReportMulti(HttpServletRequest request,
HttpServletResponse response) throws Exception {
String uri = request.getRequestURI();
String format = uri.substring(uri.lastIndexOf(".") + 1);
Map model = getModel();
model.put("format", format);
return new ModelAndView("simpleReportMulti", model);
}
In this example, the mapping key is determined from the extension of the request URI and is added to the model under the default format key: format. If you wish to use a different format key then you can configure this using the formatKey property of the JasperReportsMultiFormatView class.
By default the following mapping key mappings are configured in JasperReportsMultiFormatView:
Table 13.3. JasperReportsMultiFormatView Default Mapping Key Mappings
Mapping Key View Class
csv JasperReportsCsvView
html JasperReportsHtmlView
pdf JasperReportsPdfView
xls JasperReportsXlsView
So in the example above a request to URI /foo/myReport.pdf would be mapped to the JasperReportsPdfView class. You can override the mapping key to view class mappings using the formatMappings property of JasperReportsMultiFormatView.
When using RMI, it's not possible to access the objects through the HTTP protocol, unless you're tunneling the RMI traffic. RMI is a fairly heavy-weight protocol in that it support full-object serialization which is important when using a complex data model that needs serialization over the wire. However, RMI-JRMP is tied to Java clients: It is a Java-to-Java remoting solution.
当我们ä‹É用RMIåQŒæˆ‘们ä¸å¯ä»¥é€šè¿‡httpå议讉K—®å¯¹è±¡åQŒé™¤éžä½ 打通RMI交通的隧é“。RMI 是一个éžå¸”R‡é‡çñ”åè®®åQŒåœ¨å…¶ä¸ä»–支æŒçš„æ‰€æœ‰å¯¹è±¡çš„åºåˆ—化是éžå¸¸é‡è¦çš„,当ä‹É用一个需è¦åºåˆ—化兌™”çš„å¤æ‚çš„æ•°æ®æ¨¡åž‹ã€‚然而,RMI-JRMP 是ä¾èµ–java客户端的åQšå®ƒæ˜¯java-to-java的远½E‹è§£å†Ïx–¹æ¡ˆã€?/P>
Spring's HTTP invoker is a good choice if you need HTTP-based remoting but also rely on Java serialization. It shares the basic infrastructure with RMI invokers, just using HTTP as transport. Note that HTTP invokers are not only limited to Java-to-Java remoting but also to Spring on both the client and server side. (The latter also applies to Spring's RMI invoker for non-RMI interfaces.)
Spring çš„HTTP invoker 是一个ä¸é”™çš„选择åQŒå¦‚æžœä½ éœ€è¦åŸºäºŽHTTP的远½E‹ï¼Œè€Œä¸”需è¦javaåºåˆ—化回å¤ã€‚它使用RMI invoker分äín了基¼‹€¾l“æž„åQŒä»…ä»…ä‹É用HTTPä½œäØ“ä¼ è¾“ã€‚æ³¨æ„HTTP invoker䏿˜¯ä»…ä»…é™åˆ¶¾l™java-to-java的远½E‹è€Œä¸”是在客户端和æœåŠ¡å™¨ç«¯çš„Spring.(åŽé¢çš„也应用到Spring çš„RMI invoker为éžRMI的接å?ã€?/P>
Hessian and/or Burlap might provide significant value when operating in a heterogeneous environment, because they explicitly allow for non-Java clients. However, non-Java support is still limited. Known problems include the serialization of Hibernate objects in combination with lazily initializing collections. If you have such a data model, consider using RMI or HTTP invokers instead of Hessian.
Hessian 和或 Burlapå¯ä»¥æ”¯æŒé‡è¦çš„å€û|¼Œå½“在一个异质的环境æ“作åQŒå› ä¸ÞZ»–们明¼‹®çš„å…许为éžjava 对象。然而éžjava对象是å—é™åˆ¶çš„,知é“的问题包括hibernate对象åºåˆ—化与懒汉åˆå§‹åŒ–集åˆçš„¾l“åˆä¸Šã€‚å¦‚æžœä½ æœ‰è¿™æ ïLš„æ•°æ®æ¨¡åž‹åQŒè€ƒè™‘使用RMI或HTTP invokersè€Œä¸æ˜¯Hessioan.
JMS can be useful for providing clusters of services and allowing the JMS broker to take care of load balancing, discovery and auto-failover. By default Java serialization is used when using JMS remoting but the JMS provider could use a different mechanism for the wire formatting, such as XStream to allow servers to be implemented in other technologies.
Last but not least, EJB has an advantage over RMI in that it supports standard role-based authentication and authorization and remote transaction propagation. It is possible to get RMI invokers or HTTP invokers to support security context propagation as well, although this is not provided by core Spring: There are just appropriate hooks for plugging in third-party or custom solutions here.