如何从Quartz作业中执行Struts 2 Action。如何获得容器?

时间:2012-06-01 02:05:54

标签: java struts2 quartz-scheduler

我正在尝试从Quartz作业中执行Struts2 Action - 从任何不处理HTTP请求的上下文中进行概括。

我从这里开始http://struts.apache.org/2.0.6/docs/how-can-we-schedule-quartz-jobs.html,但该文件似乎已经过时了。

我相信(但我可能错了)我已将其归结为需要获取Container对象:

import java.util.HashMap;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.DefaultActionProxyFactory;

...

HashMap ctx = new HashMap();
DefaultActionProxyFactory factory= new DefaultActionProxyFactory();
factory.setContainer(HOW DO I GET THE CONTAINER??);
ActionProxy proxy = factory.createActionProxy("", "scheduled/myjob", ctx);

一种解决方案是针对localhost发出http请求(通过TCP)。我宁愿避免这种情况。

2 个答案:

答案 0 :(得分:2)

我有点害怕提供这个答案可能会鼓励某些人这样做,但作为概念的证明并实际为任何人提供解决方案,无论出于何种原因(也许他们继承了一些被破坏的应用程序,这是需要?),需要在正常的请求上下文之外执行Struts2动作。

但是,这是一个原始的(它是一个起点,而不是一个最佳的实现),但是工作,解决方案:

首先,将这三个类添加到名为com.stackoverflow.struts2.quartz的包中:

一个简单的工作,只是要求给定的作业上下文的代理并执行它:

package com.stackoverflow.struts2.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class ActionJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {

        try {
            QuartzActionProxyFactory.getActionProxy(context).execute();
        } catch (Exception e) {
            e.printStackTrace();
            throw new JobExecutionException(e);
        }

    }

}

传递动作细节的一些常量:

package com.stackoverflow.struts2.quartz;

public class QuartzActionConstants {

    public static final String NAMESPACE = "struts.action.namespace";
    public static final String NAME = "struts.action.name";
    public static final String METHOD = "struts.action.method";

}

可以从ActionJob静态访问的自定义ActionProxyFactory:

package com.stackoverflow.struts2.quartz;

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

import org.apache.struts2.impl.StrutsActionProxyFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;

public class QuartzActionProxyFactory extends StrutsActionProxyFactory {

    private static ActionProxyFactory actionProxyFactory;

    public QuartzActionProxyFactory() {
        actionProxyFactory = this;
    }

    public static ActionProxy getActionProxy(JobExecutionContext context) throws JobExecutionException {

        ActionProxy actionProxy = null;

        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> actionParams = context.getJobDetail().getJobDataMap();
            Map<String, Object> actionContext = new HashMap<String, Object>();
            actionContext.put(ActionContext.PARAMETERS, actionParams);

            actionProxy = actionProxyFactory.createActionProxy(
                    (String) actionParams.get(QuartzActionConstants.NAMESPACE),
                    (String) actionParams.get(QuartzActionConstants.NAME), 
                    (String) actionParams.get(QuartzActionConstants.METHOD), 
                    actionContext, 
                    false, //set to false to prevent execution of result, set to true if this is desired 
                    false);

        } catch (Exception e) {
            throw new JobExecutionException(e);
        }

        return actionProxy;
    }

}

然后,在struts.xml中添加:

<bean name="quartz" type="com.opensymphony.xwork2.ActionProxyFactory" class="com.stackoverflow.struts2.quartz.QuartzActionProxyFactory"/>
<constant name="struts.actionProxyFactory" value="quartz"/>

然后,您可以使用一些简单的代码安排操作执行:

SchedulerFactory sf = new StdSchedulerFactory();
Scheduler scheduler = sf.getScheduler();
scheduler.start();
JobDetail jobDetail = new JobDetail("someActionJob", Scheduler.DEFAULT_GROUP, ActionJob.class);

@SuppressWarnings("unchecked")
Map<String, Object> jobContext = jobDetail.getJobDataMap();
jobContext.put(QuartzActionConstants.NAMESPACE, "/the/action/namespace");
jobContext.put(QuartzActionConstants.NAME, "theActionName");
jobContext.put(QuartzActionConstants.METHOD, "theActionMethod");

Trigger trigger = new SimpleTrigger("actionJobTrigger", Scheduler.DEFAULT_GROUP, new Date(), null, SimpleTrigger.REPEAT_INDEFINITELY, 1000L);
scheduler.deleteJob("someActionJob", Scheduler.DEFAULT_GROUP);
scheduler.scheduleJob(jobDetail, trigger);

就是这样。此代码将导致每秒无限期地执行操作,并且拦截器将全部触发并且将注入依赖项。当然,依赖于像HttpServletRequest这样的Servlet对象的任何逻辑或拦截器都不会正常运行,但是无论如何将这些动作安排在servlet上下文之外是没有意义的。

答案 1 :(得分:0)

您不需要HttpServletRequest来格式化freemarker中的电子邮件。请参阅以下答案。

Create multi-part message in MIME format Freemarker template via Spring 3 JavaMail

对于发送邮件,您可以使用spring将邮件组件注入Quartz作业。即使有一个RequestContextHolder类来检索HttpServlet请求,你也不会从Quartz作业中获得HttpServletRequest。