[Java]Http Get與Post函式(Apache HttpClient)

序言

要達到基本的Http get與post方法取得網站內容,Java內的URLConnection就可以達成
但我實作時發現它太過於底層,以致於我不知該如何做到關於Session狀態的延續,也就是不能夠在完成登入後,保留住登入狀態然後進入下個動作。
於是就尋求別的作法,最後發現了Apache有提供了HttpClient套件的JAR檔,能讓我們用更簡單的方式達成工作。
在此參考網路上的文章:用HttpClient來模擬瀏覽器GET,POST,加上可自動轉導的功能,包成函式。
另外再加上可用三種類型來設定傳遞的參數,並控制其連線與中斷狀態。

下載套件

HttpClient Download下載套件,選擇Binary with dependencies的版本(如4.0.1.zip),
我們需要的JAR在該壓縮檔中的lib目錄下。會用到的JAR檔有三個:
  • commons-logging-1.1.1.jar
  • httpclient-4.0.1.jar
  • httpcore-4.0.1.jar

函式原始碼

參數轉換函式
package common.control;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;

public class HTTPParseFunc {

/**
* hashMapToString
*
* @param map
* @param charset編碼
* ,如HTTP.UTF_8
* @return
* @throws UnsupportedEncodingException
*/
@SuppressWarnings("unchecked")
public static String hashMapToString(HashMap<String, String> map,
String charset) throws UnsupportedEncodingException {
StringBuffer result = new StringBuffer();
java.util.Iterator it = map.entrySet().iterator();
boolean isfirst = true;
while (it.hasNext()) {
java.util.Map.Entry entry = (java.util.Map.Entry) it.next();
if (isfirst) {
isfirst = false;
} else {
result.append("&");
}
result
.append(URLEncoder.encode(entry.getKey().toString(),
charset));
result.append("=");
result.append(URLEncoder.encode(entry.getValue().toString(),
charset));
}
return result.toString();
}
/**
* 將inputStream轉為String
*
* @param is
* inputStream
* @param charset
* 編碼,如HTTP.UTF_8
* @return inputStream的內容
* @throws UnsupportedEncodingException
*/
public static String inputStream2String(InputStream is, String charset)
throws UnsupportedEncodingException {
BufferedReader in = new BufferedReader(new InputStreamReader(is,
charset));
StringBuffer buffer = new StringBuffer();
String line = "";
try {
boolean isfirst = true;
while ((line = in.readLine()) != null) {
if (!isfirst) {
buffer.append("\n");
} else {
isfirst = false;
}
buffer.append(line);
}
} catch (IOException e) {
e.printStackTrace();
}

return buffer.toString();
}

/**
* HTTP 傳輸參數分割
* @param param 如name1=value1&name2=value2
* @return
* @throws UnsupportedEncodingException
*/
public static ArrayList<String[]> paramToArray(String param)
throws UnsupportedEncodingException {
ArrayList<String[]> arr = null;
String[] p = param.split("&");
if (param.toLowerCase().contains("&amp;")) {
ArrayList<String> p2 = new ArrayList<String>();
int j = 0;
for (int i = 0; i < p.length; i++) {
if (p[i].toLowerCase().startsWith("amp;")) {
p2.set(j - 1, p2.get(j - 1) + "&amp;" + p[i].substring(4));
j--;
}
p2.add(p[i]);
j++;
}
p2.toArray(p);
}

for (int i = 0; i < p.length; i++) {
String[] item = p[i].split("=");
if (item.length == 2) {
if (arr == null)
arr = new ArrayList<String[]>();
// item[0]=URLDecoder.decode(item[0],charset);
// item[1]=URLDecoder.decode(item[1],charset);
arr.add(item);
}
}
return arr;
}
}

HTTP連線函式
package common;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import common.control.HTTPParseFunc;

public class HTTPBaseIO {
public enum Method {
get, post
}

private DefaultHttpClient httpclient = null;
private boolean isClosedConn = false;
private String newuri = null;
private int statuscode = HttpStatus.SC_NO_CONTENT;

private HttpHost proxy = null;

private Integer timeout=null;

public HTTPBaseIO(){

}
public HTTPBaseIO(String proxyIP,int proxyPort){
setProxy(proxyIP,proxyPort);
}
public HTTPBaseIO(HttpHost proxy){
setProxy(proxy);
}

/**
* 取得使用的proxy
*/
public HttpHost getProxy() {
return proxy;
}

/**
* 設定proxy
*/
public void setProxy(HttpHost proxy) {
this.proxy = proxy;
}

/**
* 設定proxy
*
* @param ip
* proxy的IP(hostname)
* @param port
* proxy的Port
*/
public void setProxy(String ip, int port) {
if(ip!=null)
proxy = new HttpHost(ip, port);
}

/**
* 取得回應後所得到的代碼,可參考org.apache.http.HttpStatus類別
*
* @return org.apache.http.HttpStatus
*/
public int getStatuscode() {
return statuscode;
}

/**
* 如果是轉導的狀態所得到的URI
*
* @return
*/
public String getNewuri() {
return newuri;
}

public void resetNewuri() {
newuri = null;
}

/**
* 取得連線物件
*
* @return
*/
public DefaultHttpClient getHttpclient() {
return httpclient;
}

/**
* 設定連線物件
*
* @param httpclient
*/
public void setHttpclient(DefaultHttpClient httpclient) {
this.httpclient = httpclient;
}

/**
* 是否已關閉連線
*
* @return
*/
public boolean isClosedConn() {
return isClosedConn;
}

/**
* 關閉連線
*/
public void closeConn() {
closeConn(true);
}

/**
* 關閉連線
*
* @param isCloseConn
* 是否關閉
*/
public void closeConn(boolean isCloseConn) {
if (isCloseConn && httpclient != null && !isClosedConn) {
httpclient.getConnectionManager().shutdown();
httpclient = null;
isClosedConn = true;
}
}

public void setHttpConnectionFactoryTimeout(Integer milliseconds){
timeout=milliseconds;
}

/**
* 取得網頁內容
*
* @param urlpath
* 網址
* @param method
* Method.get or Method.post
* @param params
* 參數
* @param charset
* 編碼,如HTTP.UTF_8
* @param isAutoRedirect
* 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容
* @param isCloseConn
* 是否關閉連線
* @return 失敗回傳null,成功回傳網頁HTML
* @throws ClientProtocolException
* @throws IOException
*/
public String doSend(String urlpath, Method method, String params,
String charset, boolean isAutoRedirect, boolean isCloseConn)
throws ClientProtocolException, IOException {
return doSendBase(urlpath, method, StringToHttpEntity(params, charset),
charset, isAutoRedirect, isCloseConn);
}

/**
* 取得網頁內容
*
* @param urlpath
* 網址
* @param method
* Method.get or Method.post
* @param params
* 參數
* @param charset
* 編碼,如HTTP.UTF_8
* @param isAutoRedirect
* 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容
* @param isCloseConn
* 是否關閉連線
* @return 失敗回傳null,成功回傳網頁HTML
* @throws ClientProtocolException
* @throws IOException
*/
public String doSend(String urlpath, Method method,
List<NameValuePair> params, String charset, boolean isAutoRedirect,
boolean isCloseConn) throws ClientProtocolException, IOException {
return doSendBase(urlpath, method, ListToHttpEntity(params, charset),
charset, isAutoRedirect, isCloseConn);
}

/**
* 取得網頁內容
*
* @param urlpath
* 網址
* @param method
* Method.get or Method.post
* @param params
* 參數
* @param charset
* 編碼,如HTTP.UTF_8
* @param isAutoRedirect
* 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容
* @param isCloseConn
* 是否關閉連線
* @return 失敗回傳null,成功回傳網頁HTML
* @throws ClientProtocolException
* @throws IOException
*/
public String doSend(String urlpath, Method method,
HashMap<String, String> params, String charset,
boolean isAutoRedirect, boolean isCloseConn)
throws ClientProtocolException, IOException {
return doSendBase(urlpath, method,
HashMapToHttpEntity(params, charset), charset, isAutoRedirect,
isCloseConn);
}

/**
* 取得網頁內容
*
* @param urlpath
* 網址
* @param method
* Method.get or Method.post
* @param params
* 參數
* @param charset
* 編碼,如HTTP.UTF_8
* @param isAutoRedirect
* 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容
* @param isCloseConn
* 是否關閉連線
* @return 失敗回傳null,成功回傳網頁HTML
* @throws ClientProtocolException
* @throws IOException
*/
public String doSendBase(String urlpath, Method method, HttpEntity params,
String charset, boolean isAutoRedirect, boolean isCloseConn)
throws ClientProtocolException, IOException {
String responseBody = null;
HttpUriRequest httpgetpost = null;

statuscode = HttpStatus.SC_NO_CONTENT;
try {
if (httpclient == null || isClosedConn())
httpclient = new DefaultHttpClient();

if (proxy != null)
httpclient.getParams().setParameter(
ConnRoutePNames.DEFAULT_PROXY, proxy);

if(timeout!=null){
HttpParams param = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(param, timeout);
HttpConnectionParams.setSoTimeout(param, timeout);
}


if (method == Method.post) {
httpgetpost = new HttpPost(urlpath);
if (params != null) {
((HttpPost) httpgetpost).setEntity(params);
}
} else {
if (params != null) {
urlpath += "?"
+ HTTPParseFunc.inputStream2String(params.getContent(), charset);
}
httpgetpost = new HttpGet(urlpath);
}

HttpResponse response = httpclient.execute(httpgetpost);
statuscode = response.getStatusLine().getStatusCode();
if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY)
|| (statuscode == HttpStatus.SC_MOVED_PERMANENTLY)
|| (statuscode == HttpStatus.SC_SEE_OTHER)
|| (statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {
Header header = response.getFirstHeader("location");

if (header != null) {
newuri = header.getValue();
if ((newuri == null) || (newuri.equals("")))
newuri = "/";
if (isAutoRedirect) {
httpgetpost.abort();
httpgetpost = null;
responseBody = doSendBase(newuri, Method.get, null,
charset, true, false);
}
}
} else if (statuscode == HttpStatus.SC_OK) {
responseBody = HTTPParseFunc.inputStream2String(response.getEntity()
.getContent(), charset);
}
} catch (ClientProtocolException e) {
throw e;
} catch (IOException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpgetpost != null) {
httpgetpost.abort();
httpgetpost = null;
}
closeConn(isCloseConn);
}
return responseBody;
}

/**
* List<NameValuePair>轉為HttpEntity
*
* @param nvps
* @param charset
* 編碼,如HTTP.UTF_8
* @return
* @throws UnsupportedEncodingException
*/
public static HttpEntity ListToHttpEntity(List<NameValuePair> nvps,
String charset) throws UnsupportedEncodingException {
HttpEntity result = null;
if (nvps != null && nvps.size() > 0) {
result = new UrlEncodedFormEntity(nvps, charset);

}
return result;
}

/**
* String to HttpEntity(
*
* @param nvps
* @param charset
* 編碼,如HTTP.UTF_8
* @return
* @throws UnsupportedEncodingException
*/
public static HttpEntity StringToHttpEntity(String nvps, String charset)
throws UnsupportedEncodingException {
HttpEntity result = null;
if (nvps != null) {
StringEntity reqEntity = new StringEntity(nvps, charset);
reqEntity.setContentType("application/x-www-form-urlencoded");
result = reqEntity;
}
return result;
}

/**
* HashMap To HttpEntity
*
* @param nvps
* @param charset
* 編碼,如HTTP.UTF_8
* @return
* @throws UnsupportedEncodingException
*/
public static HttpEntity HashMapToHttpEntity(HashMap<String, String> nvps,
String charset) throws UnsupportedEncodingException {
HttpEntity result = null;
if (nvps != null) {
result = new StringEntity(HTTPParseFunc.hashMapToString(nvps, charset), charset);
try {
result = StringToHttpEntity(HTTPParseFunc.inputStream2String(result
.getContent(), charset), charset);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}

}

使用範例程式

package common.test;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import common.HTTPBaseIO;
import common.control.HTTPParseFunc;

public class HTTPBaseIOTest {

@Before
public void setUp() throws Exception {
}

@After
public void tearDown() throws Exception {
}

@Test
public void testDoGet() {
String urltest = "http://www.google.com.tw";
String charset = "UTF-8";
HTTPBaseIO.Method method = HTTPBaseIO.Method.get;
HTTPBaseIO reqClient = new HTTPBaseIO();
try {
String html = reqClient.doSendBase(urltest, method, null, charset,
false, false);
System.out.println(html);
if (html == null)
fail("Client get nothing");
} catch (Exception e) {
e.printStackTrace();
} finally {
reqClient.closeConn();
}
}

@Test
public void testDoPost() {
String urlserv1 = "http://localhost/Test1/Serv1";
String urlserv2 = "http://localhost/Test1/Serv2";
String charset = HTTP.UTF_8;
HTTPBaseIO.Method method = HTTPBaseIO.Method.post;
HTTPBaseIO reqClient = new HTTPBaseIO();
try {
HashMap<String, String> map = new HashMap<String, String>();
map.put("jobname", "login");
map.put("id", "aaa");
map.put("pswd", "1234");
String html = reqClient.doSend(urlserv1, method, map, charset,
false, false);
System.out.println(html);

ArrayList<String[]> arr = HTTPParseFunc.paramToArray(html);
for (int i = 0; i < arr.size(); i++)
System.out.println(arr.get(i)[0] + "=" + arr.get(i)[1]);
if (html == null)
fail("Login get nothing");

String param = "jobname=getname";
html = reqClient.doSend(urlserv1, method, param, charset, false,
false);
System.out.println(html);
if (html == null)
fail("getname get nothing");

List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("jobname", "loadserv2"));
nvps.add(new BasicNameValuePair("name", "aaa"));
reqClient.resetNewuri();
html = reqClient.doSend(urlserv1, method, nvps, charset, true,
false);
if (html == null)
fail("loadserv2 get nothing");
nvps.clear();
if (reqClient.getNewuri() != null && html != null) {
nvps.add(new BasicNameValuePair("jobname", "getname2"));
html = reqClient.doSend(urlserv2, method, nvps, charset, false,
false);
System.out.println(html);
if (html == null)
fail("Name get nothing");
nvps.clear();
}
nvps.clear();

nvps.add(new BasicNameValuePair("jobname", "Logout"));
html = reqClient.doSend(urlserv1, method, nvps, charset, false,
false);
System.out.println(html);
if (html == null)
fail("Logout get nothing");
nvps.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
reqClient.closeConn();
}
}

}

總結

在範例的地方我假設了兩個servlet用來接收傳遞的參數,這部份可能不能直接執行,不過函式我測試過是沒問題的。
使用時可選擇用Hashmap、String、或是List作為參數設定,我分別在範例中都使用過了。
轉跳時可用getNewuri函式來確認是否有取得轉跳的網址,用回傳的html來確認是否有抓到回應的內容。
PS.我發現了Apache提供的這個Client在Windows下會有連線數上限的問題(聽說好像調整XP連線數可以解決)。

[JBoss]Java的工作排程套件-Quartz

序言

作為一個Application Server,JBoss裡的應用程式開發起來主要都是被動的等待Client呼叫啟動。但實際應用上還是有可能需要有個程序能夠在特定時間執行某些命令,例如於午夜12點整進行資料的Reset這種工作。
在不依賴作業系統或是另外執行一支程式處裡工作的狀況,其實JBoss預設就有推薦使用的工作排程套件-Quartz
就Quartz的功能而言,有的功能是與Java內建的Timer重複的,但它功能更多更強大,所以相對的要做一些設定才能使用。
以下我就舉幾個我用的方法來一探Quartz的設定(當然,這不見得是最好的作法)。

開發環境

JBoss設定

JBoss內建就有Quartz的套件,但版本很老舊,從網路上得到的資訊來看,可能會有一些問題存在。
因此建議的作法是把內建的套件刪除掉,換上新的版本。
  1. 刪除Jboss下common\lib\目錄的quartz.jar檔
  2. 刪除Jboss下server發佈目錄下的quartz-ra.rar,如jboss\server\default\deploy目錄的quartz-ra.rar
  3. quartz套件的壓縮檔打開,將裡面的quartz-all-1.7.3.jar檔案複製到jboss\common\lib(或jboss\server\default\lib)

Quartz設定檔

Quartz 提供了兩種不同的方式用來把排程工作存在記憶體(RAMJobStore)或資料庫(JDBCJobStore。)中。
  • RAMJobStore:是預設的方法,因為所有資料都存在記憶體中,所以速度最快,但是如果伺服器停止後,所有排程的工作都會消失
  • JDBCJobStore:透過 JDBC 把所有工作排成資訊存在資料庫中,但代價就是效能降低和設定複雜度的提高(尤其是有參數要透過JobDataMap在工作執行時使用時)。
在這邊我使用最簡單的RAMJobStore來進行工作排程。
這時會需要建立一個設定檔【quartz-service.xml】來設定工作排程套件的參數。這個檔案會放在JBoss的發佈目錄下,如jboss\server\default\deploy
<?xml version="1.0" encoding="UTF-8"?>

<server>

<mbean code="org.quartz.ee.jmx.jboss.QuartzService" name="user:service=QuartzService,name=QuartzService">
<attribute name="JndiName">Quartz</attribute>
<attribute name="StartScheduler">true</attribute>
<attribute name="Properties">
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.xaTransacted = false

org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 4

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
</attribute>
</mbean>

</server>

工作類別

工作要執行的內容必須實作【org.quartz.Job】介面,如
package control;

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

public class MyJob implements Job {
static int jobs=0;
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
JobDataMap dataMap = arg0.getJobDetail().getJobDataMap();
Object data1 =dataMap.get("data1");
Object data2 =dataMap.get("data2");
System.out.println("Start MyJob");
System.out.println("data1="+data1);
System.out.println("data2="+data2);
}

}

排程工作

排程的方式有兩種,一種是設定多久執行工作一次(SimpleTrigger),一種是設定什麼時間要執行工作一次(CronTrigger)。
兩者最主要差別在於描述方式。相同的是兩者都可以設定排程啟動時間,結束時間,重複次數等設定。
  • 使用SimpleTrigger
 String groupName = "Default";  //工作群組
String jobName = "MySimpleJob"; //工作名稱
InitialContext ctx;
ctx = new InitialContext();
Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
//如果工作已排程,則刪除同樣工作群組-工作名稱的工作
if (scheduler.getJobDetail(jobName, groupName) != null) {
scheduler.deleteJob(jobName, groupName);
}
JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob
//設定要傳給工作的參數
jobDetail.getJobDataMap().put("data1", "Job1");
jobDetail.getJobDataMap().put("data2", jobName);
SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, groupName); //Trigger也會設定群組與名稱,但我不確定是有什麼功用
simpleTrigger.setRepeatCount(-1); //設定-1無限次重複,如果設為0則就只會執行一次
simpleTrigger.setRepeatInterval(15*60*1000); //每15分鐘做一次

Calendar curCal = Calendar.getInstance();
curCal.add(Calendar.MINUTE, 10);
simpleTrigger.setStartTime(curCal.getTime()); //現在時間的10分鐘後啟動工作,如果不設定的話排程開始就會執行第一次

scheduler.scheduleJob(jobDetail, simpleTrigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
  • 使用CronTrigger
 String groupName = "Default";  //工作群組
String jobName = "MyCronJob"; //工作名稱
InitialContext ctx;
ctx = new InitialContext();
Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
//如果工作已排程,則刪除同樣工作群組-工作名稱的工作
if (scheduler.getJobDetail(jobName, groupName) != null) {
scheduler.deleteJob(jobName, groupName);
}
JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob
//設定要傳給工作的參數
jobDetail.getJobDataMap().put("data1", "Job2");
jobDetail.getJobDataMap().put("data2", jobName);
CronTrigger trigger = new CronTrigger(jobName, groupName,"0 0 0 * * ?"); //每天0點整執行
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}

在應用程式第一次被呼叫時排程工作

在Java Web Application中目前我還沒找到方法能在Jboss啟動時呼叫某個function,只能想到兩種方式當有第一個人啟動這個網站中的網頁時進行第一次的初始設定。
第一種方法是在static instance建立時在被New的物件建構函式中寫要做的工作,像是下面的程式。
但這種做法最大壞處是你沒辦法餵給它關於Web的Session、ServletContext等資訊,因為他是在Web內容還沒建立起來時就產生的。
import java.util.Calendar;

import javax.naming.InitialContext;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;

public class InitJob {
private static InitJob instance=new InitJob();
private InitJob(){
try {
String groupName = "Default"; //工作群組
String jobName = "MySimpleJob"; //工作名稱
InitialContext ctx;
ctx = new InitialContext();
Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
//如果工作已排程,則刪除同樣工作群組-工作名稱的工作
if (scheduler.getJobDetail(jobName, groupName) != null) {
scheduler.deleteJob(jobName, groupName);
}
JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob
//設定要傳給工作的參數
jobDetail.getJobDataMap().put("data1", "Job1");
jobDetail.getJobDataMap().put("data2", jobName);
SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, groupName); //Trigger也會設定群組與名稱,但我不確定是有什麼功用
simpleTrigger.setRepeatCount(-1); //設定-1無限次重複,如果設為0則就只會執行一次
simpleTrigger.setRepeatInterval(15*60*1000); //每15分鐘做一次

Calendar curCal = Calendar.getInstance();
curCal.add(Calendar.MINUTE, 10);
simpleTrigger.setStartTime(curCal.getTime()); //現在時間的10分鐘後啟動工作,如果不設定的話排程開始就會執行第一次

scheduler.scheduleJob(jobDetail, simpleTrigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
第二種方法是在Session建立時,設定一個Static 布林變數來判斷是否是第一次啟動,然後在裡面執行要做的工作,像是下面的程式。但相對付出的代價就是每個人進來時都會判斷一次。
如果要用這種方法就要再專案的web.xml中增加listener標籤,如
<?xml version="1.0" encoding="UTF-8"?>
<web-app...>
...
<listener>
<listener-class>control.InitSession</listener-class>
</listener>
...
</web-app>
程式如下
package control;

import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;

public class InitSession implements HttpSessionListener {
static boolean isInited=false;
@Override
public void sessionCreated(HttpSessionEvent arg0) {
if(!isInited){
//可取得Web相關的資訊
ServletContext servletContext = arg0.getSession().getServletContext();
HttpSession session = arg0.getSession();
//工作設定
String groupName = "Default"; //工作群組
String jobName = "MyCronJob"; //工作名稱
InitialContext ctx;
ctx = new InitialContext();
Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");
//如果工作已排程,則刪除同樣工作群組-工作名稱的工作
if (scheduler.getJobDetail(jobName, groupName) != null) {
scheduler.deleteJob(jobName, groupName);
}
JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob
//設定要傳給工作的參數
jobDetail.getJobDataMap().put("data1", "Job2");
jobDetail.getJobDataMap().put("data2", jobName);
CronTrigger trigger = new CronTrigger(jobName, groupName,"0 0 0 * * ?"); //每天0點整執行
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start();
}
isInited=true;
}
}

@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
}
}

總結

以上就是在JBoss上面我使用Quartz的使用經驗,至於是否有更好的作法或是我的作法有什麼缺陷,歡迎留言告訴我,謝謝

參考資料

這裡是關於技術的手札~

也歡迎大家到

倫與貓的足跡



到噗浪來

關心一下我唷!
by 倫
 
Copyright 2009 倫倫3號Beta-Log All rights reserved.
Blogger Templates created by Deluxe Templates
Wordpress Theme by EZwpthemes