tag:blogger.com,1999:blog-59465307047421309702024-03-06T16:20:07.273+08:00Jax 的工作紀錄除了在整理學習上的經驗,同時也能幫助其他需要的人Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.comBlogger27125tag:blogger.com,1999:blog-5946530704742130970.post-52043070405943847232023-02-21T10:33:00.000+08:002023-02-21T10:33:48.266+08:00[Python] Flask Log 配置<pre class="py" name="code">
import os
import logging
import logging.handlers
from flask import Flask, g, request, json
app = Flask(__name__)
#[ Log 配置 ]#############################################################
# 用來記錄無法處理的錯誤 (PS: 使用 WSGI 會依附 Apache 的設定,可以不用配置)
# https://docs.python.org/zh-cn/3/library/logging.html
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
# https://docs.python.org/zh-tw/3/library/logging.handlers.html#timedrotatingfilehandler
handler = logging.handlers.TimedRotatingFileHandler("log/web-api",
when = "D",
interval = 1,
backupCount = 7,
encoding = "UTF-8",
delay = False,
utc = True)
handler.setFormatter(formatter)
app.logger.addHandler(handler)
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-62056537356998405962023-02-21T10:13:00.000+08:002023-02-21T10:13:02.767+08:00[Python] Flask 自訂日期的 Json 轉換<pre class="py" name="code">
import os
import datetime
import time
from flask import Flask, g, request, json
from flask.json import JSONEncoder
class CustomJsonEncoder(JSONEncoder):
# 針對日期自訂 Json 轉換
def default(self, obj):
if isinstance(obj, datetime.date):
return obj.isoformat().replace('T', ' ')
return super().default(obj)
app = Flask(__name__)
app.json_encoder = CustomJsonEncoder
app.config['JSON_AS_ASCII'] = False # 返回結果可以正確顯示中文
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-37827215386294788392023-02-21T10:05:00.001+08:002023-02-21T10:05:41.641+08:00[Python] Flask MySQL 連線管理<pre class="py" name="code">
import os
import mysql.connector as sql
from werkzeug.exceptions import HTTPException, BadRequest
from flask import Flask, g, request, json
app = Flask(__name__)
#[ DB 處裡 ]#############################################################
# https://docsxyz.com/zh-hant/wiki/python/connector-python-connectargs
db_config = {
'host' : "localhost",
'user' : "XXXX",
'passwd' : "XXXX",
'db' : 'XXXX',
'use_pure' : True,
'autocommit': True,
'charset' : 'utf8',
}
@app.before_request
def before_request():
# 在 request 前開啟 DB 連線
# g 是 Flask global 在每個 request 有獨立的 context
g.cnt = sql.connect(**db_config)
g.cursor = g.cnt.cursor(dictionary = True)
@app.after_request
def after_request(response):
# 在 request 後結束 DB 連線
cursor = g.get('cursor', None)
if cursor is not None:
# 當 cursor 還有 row 沒有取出,close 會發生錯誤
if cursor.with_rows : cursor.fetchall()
cursor.close()
cnt = g.get('cnt', None)
if cnt is not None:
cnt.close()
return response
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-10516264971700766422023-02-21T09:55:00.006+08:002023-02-21T10:07:38.756+08:00[Python] Flask 筆記<div>相依套件:</div><div>-------------------------------------------------------------------------------</div><div>python-3.8.10-amd64.exe</div><div><br /></div><div>pip install Flask</div><div>pip install flask_cors</div><div>pip install mysql-connector-python</div><div>pip install pycryptodomex</div><div>pip install py-linq # <a href="https://viralogic.github.io/py-enumerable/">https://viralogic.github.io/py-enumerable/</a></div><div><br /></div><div><br /></div><div>Apache CGI 配置,用虛擬 Script 指向到 app.cgi</div><div>-------------------------------------------------------------------------------</div><div><br /></div><div><a href="https://dormousehole.readthedocs.io/en/latest/deploying/cgi.html">https://dormousehole.readthedocs.io/en/latest/deploying/cgi.html</a></div><div><a href="https://flask.palletsprojects.com/en/2.0.x/deploying/cgi/">https://flask.palletsprojects.com/en/2.0.x/deploying/cgi/</a></div><div><br /></div><div>ScriptAlias /web-api D:/iog-project/web-api/app.cgi</div><div><br /></div><div><Directory "D:/iog-project/web-api/"></div><div><span style="white-space: pre;"> </span>Options ExecCGI </div><div><span style="white-space: pre;"> </span>AllowOverride all</div><div><span style="white-space: pre;"> </span>Require local</div><div></Directory></div><div><br /></div><div><br /></div><div>執行程式 <a href="https://www.maxlist.xyz/2020/04/30/flask-helloworld/">https://www.maxlist.xyz/2020/04/30/flask-helloworld/</a></div><div>-------------------------------------------------------------------------------</div><div><br /></div><div><span style="color: #274e13;"># 正常執行</span></div><div>flask run</div><div><br /></div><div><span style="color: #274e13;"># 除錯執行 (flask 會提供除錯功能,並將 logger 從 warning 提升到 debug </span></div><div>export FLASK_ENV=development <span style="color: #274e13;"> # for linux / git bash </span></div><div>set FLASK_ENV=development <span style="color: #274e13;"># for windows cmd</span></div><div>flask run</div><div><br /></div><div><span style="color: #274e13;"># 列出設定的路徑</span></div><div>flask routes</div><div><br /></div><div><br /></div><div>其他</div><div>-------------------------------------------------------------------------------</div><div><br /></div><div>因為 web-api 的格式是 Json,所以遵照 JS 的命名風格,欄位名稱開頭小寫第二個字大寫</div><div><br /></div>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-19679640982767146202023-02-21T09:53:00.000+08:002023-02-21T09:56:06.940+08:00[Python] Flask 錯誤處裡<pre class="py" name="code">
from werkzeug.exceptions import HTTPException, BadRequest
from flask import Flask, g, request, json
app = Flask(__name__)
#[ 錯誤處裡 ]#############################################################
@app.errorhandler(Exception)
def handle_exception(e):
if isinstance(e, HTTPException): return e # 讓 HTTPException 交由下一個處理
app.logger.exception("Internal Server Error.") # log 錯誤訊息
if app.debug : return e
return json.jsonify({'message': 'Internal Server Error.'}), 500
@app.errorhandler(HTTPException)
def handle_exception(e):
response = e.get_response()
return json.jsonify({'message': e.description}), e.code
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-62403264463309707592019-07-22T16:49:00.001+08:002023-02-25T21:22:54.297+08:00C# COM 元件使用 MTA先前有用到一個通訊用的 COM 元件,因為連線不穩的時候會影響到 Main Thread 造成這個 WinForm UI 卡住,連帶所有 Main Thread 下的其他 Thread 都卡住,最先找到的方法是在 Program Main 上改用 MTAThreadAttribute,的確是可以解決卡住的問題。<br />
<br />
但 WPF 就不可以用 MTAThreadAttribute,因為 WPF 必須執行在 STAThread 的環境上,又開始苦惱這個問題了,問題應該還是有解套的辦法的只是知識不足,最後在 WIKI 中看到重要的知識。<br />
<br />
<a href="https://zh.wikipedia.org/wiki/%E7%BB%84%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%A8%A1%E5%9E%8B">WIKI 元件物件模型</a><br />
<blockquote>一個COM物件只能存在於一個套間。COM物件一經建立就確定所屬套間,並且直到銷毀它一直存在於這個套間。</blockquote><br />
所以只要用其他 Thread 去建立 COM 元件就不會影響到 Main Thread 了,簡單的解決問題,果然是知識不足。<br />
<br />
<pre class="cs" name="code">ActEasyIF actConnection;
var waiter = new AutoResetEvent(false);
new Thread(() =>
{
/* 建構 COM 元件 */
_actConnection = new ActEasyIF();
waiter.Set();
}).Start();
waiter.WaitOne(500); /* 等待建立結束 */
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-66960375027564454702019-07-22T15:36:00.003+08:002023-02-25T21:23:49.483+08:00C# struct 轉換到 byte arrayStructLayout: <a href="https://docs.microsoft.com/zh-tw/dotnet/api/system.runtime.interopservices.layoutkind?view=netframework-4.8">https://docs.microsoft.com/zh-tw/dotnet/api/system.runtime.interopservices.layoutkind?view=netframework-4.8</a><br />
Pack: 資料欄位的對齊,這會影響最短欄位的 byte 長度 <br />
<br />
<pre class="cs" name="code">[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct PollResponse
{
public int AppId;
public byte Serial;
public short Station;
}
void Main()
{
var data = new PollResponse
{
AppId = 1,
Serial = 2,
Station = 3,
};
Type type = typeof(PollResponse);
int size = Marshal.SizeOf(type);
var bytes = new byte[size];
/* struct to byte array */
IntPtr ptrIn = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(data, ptrIn, true);
Marshal.Copy(ptrIn, bytes, 0, size);
Marshal.FreeHGlobal(ptrIn);
BitConverter.ToString(bytes).Dump();
/* 01-00-00-00 - 02 - 03-00 */
/* byte array to struct */
IntPtr ptrOut = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptrOut, size);
var result = (PollResponse)Marshal.PtrToStructure(ptrOut, type);
Marshal.FreeHGlobal(ptrOut);
result.Dump();
/* { AppId = 1, Serial = 2, Station = 3 } */
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com2tag:blogger.com,1999:blog-5946530704742130970.post-16889273128667775182019-07-21T17:21:00.001+08:002023-02-25T21:25:17.785+08:00C# 讓 Dequeue 更方便的擴充方法<pre class="cs" name="code">void Main()
{
var queue = new Queue<int>();
for (int i = 0; i < 10; i++) { queue.Enqueue(i); }
string.Join(",", queue).Dump(); /* 0,1,2,3,4,5,6,7,8,9 */
var take = queue.EnumerateDequeue().Take(4).ToList();
string.Join(",", take).Dump(); /* 0,1,2,3 */
string.Join(",", queue).Dump(); /* 4,5,6,7,8,9 */
var take2 = queue.EnumerateDequeue().Take(40).ToList();
string.Join(",", take2).Dump(); /* 4,5,6,7,8,9 */
string.Join(",", queue).Dump(); /* */
}
public static class QueueExtensions
{
public static IEnumerable<T> EnumerateDequeue<T>(this Queue<T> source)
{
while (source.Count > 0) { yield return source.Dequeue(); }
}
public static IEnumerable<T> EnumerateDequeue<T>(this ConcurrentQueue<T> source)
{
T outValue;
while (source.TryDequeue(out outValue)) { yield return outValue; }
}
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-75237912172615681402019-07-21T17:06:00.001+08:002023-02-25T21:25:28.580+08:00C# 在 Enum 上增加附加資訊C# 的 Enum 是個很方便的類型,如果可以再增加額外的資訊就更方便了,這裡利用 Attribute 去定義 Enum 額外的資訊,再用擴充方法取得 Enum 所屬的資訊。<br />
<br />
用 Attribute 來定義有個好處,未來在增減 Enum 時可以一起進行修改,不用擔心會有遺漏而沒修改的問題。<br />
<br />
<pre class="cs" name="code">void Main()
{
PortAreaCode.F1Front.GetFloor().Dump(); /* F1 */
}
public enum PortAreaCode
{
[AreaMeta("None", 0)]
None,
[AreaMeta("F1", 1)]
F1Front,
[AreaMeta("F2", 1)]
F2Front,
}
/// <summary>PortAreaCode 額外附屬資訊定義的 Attribute</summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
class AreaMetaAttribute : Attribute
{
public string Floor { get; private set; }
public int WarehouseId { get; private set; }
public AreaMetaAttribute() : this("None", 0) { }
public AreaMetaAttribute(string floor, int warehouseId)
{
Floor = floor;
WarehouseId = warehouseId;
}
}
/// <summary>PortAreaCode 的擴充方法</summary>
public static class PortAreaCodeExtensions
{
private static AreaMetaAttribute _defaultMeta = new AreaMetaAttribute();
private static AreaMetaAttribute getMeta(PortAreaCode value)
{
FieldInfo field = typeof(PortAreaCode).GetField(value.ToString());
if(field == null) { return _defaultMeta; }
var meta = field.GetCustomAttribute<AreaMetaAttribute>();
return meta ?? _defaultMeta;
}
public static string GetFloor(this PortAreaCode value)
{
return getMeta(value).Floor;
}
public static int GetWarehouseId(this PortAreaCode value)
{
return getMeta(value).WarehouseId;
}
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-69576319686720862622019-07-21T16:29:00.001+08:002023-02-25T21:25:37.495+08:00C# 用 gzip 壓縮字串並取得 base64 字串這個使用方式的效果是有但書的,當 Source 的重複率不高壓縮的效果就不會好,再加上 base64 就是用可見文字去表示 byte 值,這會讓 base64 後的結果比 byte array 還要長,所以壓縮率沒有到達一定的程度下,輸出反而會比 Source 的字串還要長。<br />
<br />
<pre class="cs" name="code">//using System.IO.Compression;
void Main()
{
string text = "OptionPostal,OptionClassType,OptionTalentItem";
text.Length.Dump(); /* 45 */
string compressBase64 = compress(text);
compressBase64.Length.Dump(); /* 76 */
compressBase64.Dump();
/* H4sIAAAAAAAEAPMvKMnMzwvILy5JzNHxB3OccxKLi0MqC1Kh/JDEnNS8Es+S1FwAaY6qVC0AAAA= */
string decompressText = decompress(compressBase64);
decompressText.Dump();
/* OptionPostal,OptionClassType,OptionTalentItem */
text = "OptionPostal,OptionClassType,OptionTalentItem,OptionPostal,OptionClassType,OptionTalentItem,OptionPostal,OptionClassType,OptionTalentItem,OptionPostal,OptionClassType,OptionTalentItem";
text.Length.Dump(); /* 183 */
compressBase64 = compress(text);
compressBase64.Length.Dump(); /* 84 */
compressBase64.Dump();
/* H4sIAAAAAAAEAPMvKMnMzwvILy5JzNHxB3OccxKLi0MqC1Kh/JDEnNS8Es+S1FyowCBQDQBPmlWktwAAAA== */
}
/*壓縮*/
private static string compress(string text)
{
if (string.IsNullOrEmpty(text)) { return text; }
byte[] buffer = Encoding.UTF8.GetBytes(text);
using (var outStream = new MemoryStream())
using (var zip = new GZipStream(outStream, CompressionMode.Compress))
{
zip.Write(buffer, 0, buffer.Length);
zip.Close();
string compressedBase64 = Convert.ToBase64String(outStream.ToArray());
return compressedBase64;
}
}
/*解壓縮*/
private static string decompress(string compressed)
{
if (string.IsNullOrEmpty(compressed)) { return compressed; }
byte[] buffer = Convert.FromBase64String(compressed);
using (var inStream = new MemoryStream(buffer))
using (var outStream = new MemoryStream())
using (var zip = new GZipStream(inStream, CompressionMode.Decompress))
{
zip.CopyTo(outStream);
zip.Close();
string text = Encoding.UTF8.GetString(outStream.ToArray());
return text;
}
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-68378234918702632672019-07-21T15:53:00.003+08:002023-02-25T21:25:43.779+08:00產生 IP v6 的 mask byte array<pre class="cs" name="code">int length = 121; /* total 128 */
var mask = new byte[16];
for (int i = 0; i < 16; i++)
{
mask[i] = 0xff;
if (length > -8) { length -= 8; }
if (length < 0) { mask[i] = (byte)(mask[i] << -length); }
/* 當 length 出現負值時代表需要進行位移 */
}
BitConverter.ToString(mask).Dump();
/* FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-80 */
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-56275614163885295172019-07-21T15:43:00.003+08:002023-02-25T21:25:57.789+08:00C# DateTimeOffset Parse PatchDateTimeOffset 在 Parse 時會使用 Local TimeZone,這會與期望的 TimeZone 產生偏差,需要進行差值修補。<br />
<br />
<pre class="cs" name="code">//TimeZoneInfo.GetSystemTimeZones().Dump();
/* (UTC+02:00) 開羅 */
var zone = TimeZoneInfo.FindSystemTimeZoneById("Egypt Standard Time");
zone.Dump();
var date = DateTimeOffset.Parse("2019-07-01 15:00:00");
date.Dump(); /* 2019/7/1 下午 03:00:00 +08:00 */
var diff = date.Offset - zone.BaseUtcOffset;
diff.Dump(); /* 06:00:00 */
date = date.Add(diff);
date.Dump(); /* 2019/7/1 下午 09:00:00 +08:00 */
date = TimeZoneInfo.ConvertTime(date, zone);
date.Dump(); /* 2019/7/1 下午 03:00:00 +02:00 */
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-43909466944523068672015-03-13T13:12:00.002+08:002015-03-13T14:40:27.893+08:00[Java] Ant zip 解壓縮筆記<pre class="xml:nogutter:nocontrols" name="code"><unzip dest="./target_dir">
<!-- 來源的壓縮檔 -->
<fileset dir="lib">
<include name="tiles-jsp-*.jar"/>
</fileset>
<!-- 要解出的檔案 -->
<patternset>
<include name="**/*.tld"/>
</patternset>
<!-- 解出路徑的轉換 -->
<mapper type="flatten"/>
</unzip>
</pre><br />
參考文件:<br />
<a href="https://ant.apache.org/manual/Tasks/unzip.html" target="_blank">Apache Ant™ User Manual : Unzip Task</a><br />
<a href="https://ant.apache.org/manual/Types/mapper.html" target="_blank">Apache Ant™ User Manual : Mapper</a><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-48086193485153050832015-03-13T11:59:00.000+08:002015-03-13T14:40:27.899+08:00[Java] Reflection 筆記<pre class="java:nogutter:nocontrols" name="code">@SuppressWarnings("unused")
Object obj = new Object() {
String id = "123";
public String name = "Jax";
};
Class<?> cl = obj.getClass();
for (Field field : cl.getFields()) {
System.out.printf("%s = %s {%s}\n",
field.getName(), field.get(obj), field.getType());
}
System.out.println("=======================");
for (Field field : cl.getDeclaredFields()) {
System.out.printf("%s = %s {%s}\n",
field.getName(), field.get(obj), field.getType());
}
</pre><br />
Output:<br />
<pre class="none:nogutter:nocontrols" name="code">name = Jax {class java.lang.String}
=======================
id = 123 {class java.lang.String}
name = Jax {class java.lang.String}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-18662793205287362292015-03-06T17:12:00.000+08:002015-03-13T14:40:27.874+08:00[Java] 製作縮圖筆記<pre class="java:nogutter:nocontrols" name="code">package test_image;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
public class TestImageResize {
private static int targetWidth = 120;
private static int targetHeight = 80;
private static double targetRate = (double) targetWidth / targetHeight;
public static void main(String[] args) throws Exception {
System.out.printf("Target w:%s, h:%s, r:%s\n",
targetWidth, targetHeight, targetRate);
BufferedImage image = ImageIO.read(new File("input.jpg"));
int type = image.getType();
if(type == 0) { type = BufferedImage.TYPE_INT_ARGB; }
int width = image.getWidth();
int height = image.getHeight();
double rate = (double) width / height;
System.out.printf("Source w:%s, h:%s, r:%s\n", width, height, rate);
/* 等比例縮小至指定大小內 */
int rWidth = targetWidth;
int rHeight = targetHeight;
if(width < targetWidth && height < targetHeight) {
rWidth = width;
rHeight = height;
} else if(rate > targetRate) {
rHeight = (int) (targetWidth / rate);
} else {
rWidth = (int) (targetHeight * rate);
}
System.out.printf("Resize w:%s, h:%s\n", rWidth, rHeight);
BufferedImage resize1 = new BufferedImage(rWidth, rHeight, type);
Graphics g1 = resize1.getGraphics();
g1.drawImage(image, 0, 0, rWidth, rHeight, null);
g1.dispose();
ImageIO.write(resize1, "jpg", new File("output_1.jpg"));
/* 等比例縮小填滿指定大小 */
BufferedImage resize2 = new BufferedImage(targetWidth,targetHeight,type);
Graphics g2 = resize2.getGraphics();
int startX = 0;
int startY = 0;
int size = 0;
if(rate > targetRate) {
startX = (int) (width - height * targetRate) / 2;
size = height;
} else {
startY = (int) (height - width / targetRate) / 2;
size = width;
}
System.out.printf("x:%s, y:%s, size:%s\n", startX, startY, size);
g2.drawImage(
image,
0, 0, targetWidth, targetHeight,
startX, startY, (size + startX), (size + startY),
null
);
g2.dispose();
ImageIO.write(resize2, "jpg", new File("output_2.jpg"));
}
}
</pre><br />
參考文件:<br />
<a href="http://nothing.tw/JDK_API_1_6/java/awt/Graphics.html" target="_blank">Graphics (Java 2 Platform SE 6)</a><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-16494669802506525802015-03-06T15:33:00.001+08:002015-03-13T14:40:27.869+08:00[Java] Jsoup 筆記<pre class="java" name="code">import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class TestJsoup {
public static void main(String[] args) throws Exception {
String url = "http://epg.dishstar.net/calendar.php?s=DISC&d=1";
// Document doc = Jsoup.parse(new URL(url), 5000);
Document doc = Jsoup.connect(url)
.userAgent("Mozilla/5.0")
.timeout(5000).get();
Elements trs = doc.select("table tr");
for (Element tr : trs) {
String time = tr.select("td:eq(0)").text();
String title = tr.select("td:eq(1)").text();
System.out.println(time + " <=> " + title);
}
}
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-59790078868821735492015-03-06T11:57:00.001+08:002015-03-13T14:40:27.907+08:00Spring JavaMail 筆記<strong>Gmail via SSL</strong><br />
<pre class="xml" name="code"><bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="465" />
<property name="username" value="smtp-user" />
<property name="password" value="smtp-passwd" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
</pre><br />
<br />
<strong>Gmail via TLS</strong><br />
<pre class="xml" name="code"><bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="port" value="587" />
<property name="username" value="smtp-user" />
<property name="password" value="smtp-passwd" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.starttls.enable">true</prop>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
</pre><br />
<br />
<strong>Sample Code</strong><br />
<pre class="java:nogutter:nocontrols" name="code">package test_mail;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
public class TestSpringMail {
public static void main( String[] args ) throws Exception {
AbstractApplicationContext context
= new ClassPathXmlApplicationContext("test_mail/spring-mail.xml");
JavaMailSender mailSender
= (JavaMailSender) context.getBean("mailSender");
sample1(mailSender);
sample2(mailSender);
sample3(mailSender);
context.close();
}
public static void sample1(JavaMailSender mailSender) throws Exception {
MimeMessage mimeMessage = mailSender.createMimeMessage();
mimeMessage.setFrom("from@no-spam.com");
mimeMessage.setRecipients(
Message.RecipientType.TO, "to@no-spam.com"
);
mimeMessage.setSubject("Testing Subject");
mimeMessage.setContent(
"<b>Testing Content.</b>",
"text/html; charset=utf-8"
);
mailSender.send(mimeMessage);
}
public static void sample2(JavaMailSender mailSender) throws Exception {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, "utf-8");
message.setFrom("from@no-spam.com");
message.setTo("to@no-spam.com");
message.setSubject("Testing Subject");
message.setText("<b>Testing Content.</b>", true);
mailSender.send(mimeMessage);
}
public static void sample3(JavaMailSender mailSender) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("from@no-spam.com");
message.setTo("to@no-spam.com");
message.setSubject("Testing Subject");
message.setText("Testing Content.");
mailSender.send(message);
}
}
</pre><br />
<br />
參考自:<br />
<a href="http://www.mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/" target="_blank">JavaMail API – Sending email via Gmail SMTP example : Mkyong</a><br />
<a href="http://www.mkyong.com/spring/spring-sending-e-mail-with-attachment/" target="_blank">Spring – Sending e-mail with attachment : Mkyong</a><br />
<a href="http://www.mkyong.com/spring/spring-define-an-e-mail-template-in-bean-configuration-file/" target="_blank">Spring – Define an E-mail template in bean configuration file : Mkyong</a><br />
<a href="http://www.mkyong.com/spring/spring-sending-e-mail-via-gmail-smtp-server-with-mailsender/" target="_blank">Spring – Sending E-mail via Gmail SMTP server with MailSender : Mkyong</a><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-34341042884506955832015-03-04T11:33:00.002+08:002015-03-13T14:40:27.887+08:00[Java] FileFilter 筆記<pre class="java:nogutter:nocontrols" name="code">File dir = new File("D:/log");
File[] list = dir.listFiles(new FileFilter(){
public boolean accept(File file) {
return file.getName().endsWith(".txt");
}
});
for(File file : list){
System.out.println(file.getAbsoluteFile());
}
// 004.txt
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-91231883166810473952015-03-04T11:23:00.000+08:002015-03-13T14:40:27.925+08:00[Java] Object Serializable 筆記<pre class="java:nogutter:nocontrols" name="code">import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Address implements Serializable {
private static final long serialVersionUID = 1L;
String street;
String country;
public Address() {}
public Address(String s, String c) {
street = s; country = c;
}
public void setStreet(String street){ this.street = street; }
public String getStreet(){ return this.street; }
public void setCountry(String country){ this.country = country; }
public String getCountry(){ return this.country; }
@Override
public String toString() {
return String.format("Street : %s Country : %s", street, country);
}
}
public class TestSerializable {
public static void main(String[] args) throws Exception {
Address addr = new Address("wall street", "united state");
FileOutputStream fout = new FileOutputStream("address.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(addr);
oos.close();
FileInputStream fin = new FileInputStream("address.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
Address addr2 = (Address) ois.readObject();
ois.close();
System.out.println(addr2);
// Street : wall street Country : united state
}
}
</pre><br />
參考自:<br />
<a href="http://www.mkyong.com/java/how-to-read-an-object-from-file-in-java/" target="_blank">How to read an Object from file in Java : Mkyong</a><br />
<a href="http://www.mkyong.com/java/how-to-write-an-object-to-file-in-java/" target="_blank">How to write an Object to file in Java : Mkyong</a><br />
<a href="http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/" target="_blank">Understand the serialVersionUID : Mkyong</a>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-83209673505296905892015-03-01T20:14:00.000+08:002015-03-13T14:40:27.920+08:00[Java] Jackson Json Parser 筆記 <strong>Object Encode / Decode</strong><br />
<pre class="java:nocontrols" name="code">import java.util.Arrays;
import java.util.Date;
import com.fasterxml.jackson.databind.ObjectMapper;
class Album {
private int id;
private String title;
private Date date;
private String[] list;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
public String[] getList() { return list; }
public void setList(String[] list) { this.list = list; }
@Override
public String toString() {
return String.format("id: %s, title: %s, date: %s, list: %s",
id, title, date, Arrays.toString(list)
);
}
}
public class TestJackson {
public static void main(String[] args) throws Exception {
Album album = new Album();
album.setId(1);
album.setTitle("Go Go Go!");;
album.setDate(new Date());
album.setList(new String[]{"Love", "Despair"});
ObjectMapper jsonMapper = new ObjectMapper();
String json = jsonMapper.writeValueAsString(album);
System.out.println(json);
// {"id":1,"title":"Go Go Go!","date":1425211903948,"list":["Love","Despair"]}
Album album2 = jsonMapper.readValue(json, Album.class);
System.out.println(album2);
// id: 1, title: Go Go Go!, date: Sun Mar 01 20:11:43 CST 2015, list: [Love, Despair]
}
}
</pre><br />
<br />
<strong>Parser to Map</strong><br />
<pre class="java:nogutter:nocontrols" name="code">ObjectMapper jsonMapper = new ObjectMapper();
Map<String,String> map;
map = jsonMapper.readValue(
"{\"name\":\"jax\", \"age\":\"31\"}",
new TypeReference<HashMap<String,String>>(){}
);
System.out.println(map);
// {age=31, name=jax}
jsonMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
jsonMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
map = jsonMapper.readValue(
"{name:'jax', age:'31'}",
new TypeReference<HashMap<String,String>>(){}
);
System.out.println(map);
// {age=31, name=jax}
</pre><br />
<br />
<strong>Encode Date</strong> <br />
<pre class="java:nogutter:nocontrols" name="code">Date date = new Date();
String json;
ObjectMapper jsonMapper = new ObjectMapper();
json = jsonMapper.writeValueAsString(date);
System.out.println(json);
// 1425211840183
jsonMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
json = jsonMapper.writeValueAsString(date);
System.out.println(json);
// "2015-03-01T12:10:40.183+0000"
</pre><br />
參考自:<a href="https://github.com/FasterXML/jackson-databind/" target="_blank">FasterXML/jackson-databind · GitHub</a><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com3tag:blogger.com,1999:blog-5946530704742130970.post-14617209528995993952015-02-22T19:34:00.000+08:002015-03-13T14:40:27.864+08:00[Java] URL 筆記Request URL<br />
<code>http://user:passwd@30thh.loc:8480/test%3F+b;?p+1=c+d&p+2=e+f#ref</code><br />
<br />
<table class="table_list" cellspacing="0" cellpadding="4" border="1"><tr class="header"><th>Method</th><th>Result</th></tr>
<tr><td><b>getAuthority()</b></td><td>user:passwd@30thh.loc:8480</td></tr>
<tr><td><b>getDefaultPort()</b></td><td>80</td></tr>
<tr><td><b>getFile()</b></td><td>/test%3F+b;?p+1=c+d&p+2=e+f</td></tr>
<tr><td><b>getHost()</b></td><td>30thh.loc</td></tr>
<tr><td><b>getPath()</b></td><td>/test%3F+b;</td></tr>
<tr><td><b>getPort()</b></td><td>8480</td></tr>
<tr><td><b>getProtocol()</b></td><td>http</td></tr>
<tr><td><b>getQuery()</b></td><td>p+1=c+d&p+2=e+f</td></tr>
<tr><td><b>getRef()</b></td><td>ref</td></tr>
<tr><td><b>getUserInfo()</b></td><td>user:passwd</td></tr>
<tr><td><b>toString()</b></td><td>http://user:passwd@30thh.loc:8480/test%3F+b;?p+1=c+d&p+2=e+f#ref</td></tr>
</table><br />
<pre class="java:nogutter:nocontrols" name="code">URL base1 = new URL("http://localhost:8090/home/");
System.out.println(new URL(base1,"Service.json"));
// http://localhost:8090/home/Service.json
System.out.println(new URL(base1,"/Service.json"));
// http://localhost:8090/Service.json
System.out.println(new URL(base1,"./Service.json"));
// http://localhost:8090/home/Service.json
URL base2 = new URL("http://localhost:8090/home/index");
System.out.println(new URL(base2,"Service.json"));
// http://localhost:8090/home/Service.json
System.out.println(new URL(base2,"/Service.json"));
// http://localhost:8090/Service.json
System.out.println(new URL(base2,"./Service.json"));
// http://localhost:8090/home/Service.json
</pre><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-2388600091900395332015-02-21T11:03:00.000+08:002015-03-13T14:40:27.882+08:00[Java] System Property 筆記<code>String version = System.getProperty("java.version");</code><br />
<br />
<table class="table_list" cellspacing="0" cellpadding="4" border="1"><tr><td><b>java.version</b></td><td>Java 執行期環境版本</td></tr>
<tr><td><b>java.vendor</b></td><td>Java 執行期環境供應商</td></tr>
<tr><td><b>java.vendor.url</b></td><td>Java 供應商的 URL</td></tr>
<tr><td><b>java.home</b></td><td>Java 安裝目錄</td></tr>
<tr><td><b>java.vm.specification.version</b></td><td>Java 虛擬機規範版本</td></tr>
<tr><td><b>java.vm.specification.vendor</b></td><td>Java 虛擬機規範供應商</td></tr>
<tr><td><b>java.vm.specification.name</b></td><td>Java 虛擬機規範名稱</td></tr>
<tr><td><b>java.vm.version</b></td><td>Java 虛擬機實現版本</td></tr>
<tr><td><b>java.vm.vendor</b></td><td>Java 虛擬機實現供應商</td></tr>
<tr><td><b>java.vm.name</b></td><td>Java 虛擬機實現名稱</td></tr>
<tr><td><b>java.specification.version</b></td><td>Java 執行期環境規範版本</td></tr>
<tr><td><b>java.specification.vendor</b></td><td>Java 執行期環境規範供應商</td></tr>
<tr><td><b>java.specification.name</b></td><td>Java 執行期環境規範名稱</td></tr>
<tr><td><b>java.class.version</b></td><td>Java 類別格式版本號</td></tr>
<tr><td><b>java.class.path</b></td><td>Java 類別路徑</td></tr>
<tr><td><b>java.library.path</b></td><td>加載庫時搜索的路徑串列(linked-list)</td></tr>
<tr><td><b>java.io.tmpdir</b></td><td>預設的暫時檔路徑</td></tr>
<tr><td><b>java.compiler</b></td><td>要使用的 JIT 編譯器的名稱</td></tr>
<tr><td><b>java.ext.dirs</b></td><td>一個或多個擴展目錄的路徑</td></tr>
<tr><td><b>os.name</b></td><td>作業系統 的名稱</td></tr>
<tr><td><b>os.arch</b></td><td>作業系統 的架構</td></tr>
<tr><td><b>os.version</b></td><td>作業系統 的版本</td></tr>
<tr><td><b>file.separator</b></td><td>檔分隔設定(在 UNIX 系統中是“/”)</td></tr>
<tr><td><b>path.separator</b></td><td>路徑分隔設定(在 UNIX 系統中是“:”)</td></tr>
<tr><td><b>line.separator</b></td><td>行分隔設定(在 UNIX 系統中是“/n”)</td></tr>
<tr><td><b>user.name</b></td><td>用戶的賬戶名稱</td></tr>
<tr><td><b>user.home</b></td><td>用戶的主目錄</td></tr>
<tr><td><b>user.dir</b></td><td>用戶的當前工作目錄</td></tr>
</table><br />
<br />
List all system properties<br />
<pre class="java:nogutter:nocontrols" name="code">Properties props = System.getProperties();
props.list(System.out);
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-65800934333611722542015-02-21T10:55:00.002+08:002015-03-13T14:40:27.916+08:00[Java] ServletRequest 筆記Request URL<br />
<code>http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S%3F+ID?p+1=c+d&p+2=e+f#a</code><br />
<br />
<table class="table_list" cellspacing="0" cellpadding="4" border="1" style="font-size:95%"><tr class="header"><th>Method</th><th>URL Decoded</th><th>Result</th></tr>
<tr><td><b>getContextPath()</b></td><td></td><td>/app</td></tr>
<tr><td><b>getLocalAddr()</b></td><td></td><td>127.0.0.1</td></tr>
<tr><td><b>getLocalName()</b></td><td></td><td>30thh.loc</td></tr>
<tr><td><b>getLocalPort()</b></td><td></td><td>8480</td></tr>
<tr><td><b>getMethod()</b></td><td></td><td>GET</td></tr>
<tr><td><b>getPathInfo()</b></td><td>yes</td><td>/a?+b</td></tr>
<tr><td><b>getProtocol()</b></td><td></td><td>HTTP/1.1</td></tr>
<tr><td><b>getQueryString()</b></td><td>no</td><td>p+1=c+d&p+2=e+f</td></tr>
<tr><td><b>getRequestedSessionId()</b></td><td>no</td><td>S%3F+ID</td></tr>
<tr><td><b>getRequestURI()</b></td><td>no</td><td>/app/test%3F/a%3F+b;jsessionid=S+ID</td></tr>
<tr><td><b>getRequestURL()</b></td><td>no</td><td>http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S+ID</td></tr>
<tr><td><b>getScheme()</b></td><td></td><td>http</td></tr>
<tr><td><b>getServerName()</b></td><td></td><td>30thh.loc</td></tr>
<tr><td><b>getServerPort()</b></td><td></td><td>8480</td></tr>
<tr><td><b>getServletPath()</b></td><td>yes</td><td>/test?</td></tr>
<tr><td><b>getParameterNames()</b></td><td>yes</td><td>[p 2, p 1]</td></tr>
<tr><td><b>getParameter("p 1")</b></td><td>yes</td><td>c d</td></tr>
</table><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-10881327493269337092011-12-21T18:46:00.000+08:002015-03-13T14:40:27.860+08:00Aptana Scripting 學習筆記<ul><li>在任何一個專案的頂層目錄,建立一個名稱為 scripts 或 monkey 的目錄</li>
<li>在此目錄下建立副檔名為 *.js 或 *.em 的 JavaScript 的文件 </li>
</ul><br />
<strong>一個空白文件的內容如下:</strong><br />
<pre class="js" name="code">/*
* Menu: Samples > Execute Snippet
* Key: M1+M2+M3+F
* Kudos: Jax Hu
* License: EPL 1.0
* DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
*/
function main(){
}
</pre><br />
<br />
<strong>快捷鍵的代號對應:</strong><br />
<table><tr><td>M1</td><td>Control/Command</td></tr>
<tr><td>M2</td><td>Shift</td></tr>
<tr><td>M3</td><td>Alt/Option</td></tr>
</table><br />
<br />
<strong>一個可以用來顯示物件成員的函數:</strong><br />
<pre class="js" name="code">/**顯示物件的成員
* @param {Object} val 物件
*/
function var_dump(val){
var name, value, temp=[];
for (name in val) {
try {
value = (val[name]+'').
replace("function",'<b style="color:#00f;">$&</b>');
}catch (e) {
value = (e+'').fontcolor('red');
}
temp.push('<b style="color:#707;">'+name+'</b> = '+value);
}
webView = views.getView("var_dump");
webView.showView(true);
webView.setTitle('var_dump');
webView.setHTML(temp.join("<hr/>").fixed());
}
</pre><br />
<br />
<strong>常用方法以及數值:</strong><br />
<pre class="js" name="code">
/*當前文件的位置
* => D:/WorkSpace/my_project/test.js */
location
/*當前文件的名稱
* => test.js */
editors.activeEditor.title
/*當前的文件內容*/
editors.activeEditor.source
/*當前文件的 URI 位址*/
editors.activeEditor.uri
/*儲存當前文件*/
editors.activeEditor.save();
/*對當前文件-開啟另存新檔的對話匡*/
editors.activeEditor.textEditor.doSaveAs()
/*對當前文件的目錄路徑
* => D:/WorkSpace/my_project */
editors.activeEditor.textEditor.editorInput.file.parent.location
/*目前開啟的所有文件*/
editors.all[];
/*儲存全部編輯器,傳入 true 會開啟存檔提示*/
window.workbench.saveAllEditors(false);
/*重新開啟 Eclipse*/
window.workbench.restart();
/*關閉 Eclipse*/
window.workbench.close();
/* 開新的編輯器,可以透過這個開啟空白文件,或是已經存在的檔案,
* 之後 editors.activeEditor 會轉到這個文件上 */
fileUtils.open('textile_to_redmine.txt');
/*取得當前的專案名稱*/
editors.activeEditor.textEditor.editorInput.file.project.name;
/*取得所有的專案*/
Packages.org.eclipse.core.resources.ResourcesPlugin.workspace.root.projects;
editors.activeEditor.textEditor.editorInput.file.workspace.root.projects
</pre><br />
<br />
<strong>建立一個新的視圖,或開啟已存在的視圖:</strong><br />
<pre class="js" name="code">webView = views.getView("my_view_name");
/*顯示視圖*/
webView.showView(true);
/*設定標題*/
webView.setTitle("My View Title");
/*設定內容的HTML*/
webView.setHTML('<h1>OK</h1>');
/*或指定內容的網址*/
webView.url = "http://www.google.com";
webView.addEventListener("LocationChanging", function(event){
var location = event.innerEvent.location;
// Print out the location to the Java console
Packages.java.lang.System.out.println("You clicked on: " + location);
});
</pre><br />
<br />
<strong>替換選擇的文字區段:</strong><br />
<pre class="js" name="code">/*選擇的起始位置*/
var starting = editors.activeEditor.selectionRange.startingOffset;
/*選擇的結束位置*/
var ending = editors.activeEditor.selectionRange.endingOffset;
/*選擇的文字內容*/
var text = editors.activeEditor.source.substring(starting, ending);
/*文字跳脫處理,或其他自訂的處理*/
text = escape(text);
/*替換選擇的文字*/
editors.activeEditor.applyEdit(starting, ending-starting, text);
/*重新選擇文字區段*/
editors.activeEditor.selectAndReveal(starting, text.length);
</pre><br />
<br />
<strong>檔案存取:</strong><br />
<pre class="js" name="code">var file = new File("myFile.txt");
file.createNewFile();
file.write("Date: ");
var text = file.readLines();
</pre><br />
<br />
<strong>Web 資料請求的方式:</strong><br />
<pre class="js" name="code">var req = new WebRequest();
req.open("GET", "http://xml.weather.yahoo.com/forecastrss?p=94103");
var text = req.send();
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com2tag:blogger.com,1999:blog-5946530704742130970.post-51173276919070396272011-12-15T18:51:00.001+08:002015-03-13T14:40:27.903+08:00[PHP] Documentor (phpdoc) 備忘<strong>Linux 安裝指令</strong><br />
sudo pear install -o PhpDocumentor<br />
<br />
<br />
<strong>Windows 安裝指令</strong><br />
C:\wamp\bin\php\php5.2.4\pear.bat install -o PhpDocumentor <br />
<br />
<br />
<strong>使用方式</strong><br />
<pre class="sh" name="code">phpdoc --parseprivate \
--output HTML:frames:earthli \
--ignore Smarty/ \
--directory /var/www/lib,/var/www/data_mod,/var/www/etc \
--target /var/www/docs
</pre><br />
<br />
<strong>phpdoc 參數說明</strong><br />
<table><tr valign="top"><td>-f</td><td>--filename</td><td>要解析的檔案名稱,可使用 ‘,’分隔多個檔案 “file1,file2”,可以包含完整路徑和使用 * ? 萬用符號。</td></tr>
<tr valign="top"><td>-d</td><td>--directory</td><td>要解析的目錄路徑,可使用 ‘,’分隔多個目錄路徑 “directory1,directory2”。</td></tr>
<tr valign="top"><td>-t</td><td>--target</td><td>指定要輸出的目錄。</td></tr>
<tr valign="top"><td>-i</td><td>--ignore</td><td>要忽略的檔案名稱,可使用 ‘,’分隔多個檔案 “file1,file2”,可以使用 * ? 萬用符號。</td></tr>
<tr valign="top"><td>-is</td><td>--ignoresymlinks</td><td>忽略系統連結的檔案或目錄,預設是關閉的。</td></tr>
<tr valign="top"><td>-it</td><td>--ignore-tags</td><td>忽略解析的標籤。 @package, @subpackage, @access, @ignore 可能是無法忽視。</td></tr>
<tr valign="top"><td>-q</td><td>--quiet</td><td>不顯示解析/轉換的訊息,在 cron 排程時可以選擇開啟,預設是關閉的。</td></tr>
<tr valign="top"><td>-ti</td><td>--title</td><td>產生出的文件的標題,預設為 ‘Generated Documentation’。</td></tr>
<tr valign="top"><td>-h</td><td>--help</td><td>顯示幫助訊息。</td></tr>
<tr valign="top"><td>-pp</td><td>--parseprivate</td><td>將私有(private)成員函式或私有變數也都加入程式文件裡。不然產生出的文件裡只會有公開(public)和保護(protected)的成員函式和變數。</td></tr>
<tr valign="top"><td>-o</td><td>--output</td><td>設置輸出文件的格式</td></tr>
<tr valign="top"><td colspan="3"><ul><li>HTML:frames:* - 包含iframe的HTML格式</li>
<li>HTML:frames:default – Javadoc風格的文檔模板,很少有格式</li>
<li>HTML:frames:earthli – 漂亮的模板(作者:Marco von Ballmoos)</li>
<li>HTML:frames:l0l33t – 流行模板</li>
<li>HTML:frames:phpdoc.de – 類似於phpdoc.de的PHPDoc輸出</li>
<li>HTML:frames:phphtmllib – 非常棒的用戶貢獻模板</li>
<li>HTML:frames:phpedit – 基於PHPEdit Help Generator的文檔</li>
<li>HTML:Smarty:* - 不使用iframe的HTML格式</li>
<li>HTML:Smarty:default – 使用css控制的黑體模板</li>
<li>HTML:Smarty:HandS – 基於PHP的格式,但是經過優化,帶有logo圖片</li>
<li>HTML:Smarty:PHP – 風格接近PHP官網</li>
<li>CHM:default:* - 輸出CHM幫助文檔</li>
<li>CHM:default:default – windows幫助文檔,基於HTML:frames:l0l33t</li>
<li>PDF:default:* - PDF格式</li>
<li>PDF:default:default – 標準純文本PDF格式</li>
<li>XML:DocBook:* - 以DocBook格式輸出的XML</li>
<li>XML:DocBook/peardoc2:default – 可以被編譯成peardoc的文檔</li>
</ul></td></tr>
<tr valign="top"><td>-j</td><td>--javadocdesc</td><td>相容 JavaDoc 的格式,預設是關閉的</td></tr>
</table><br />
<br />
<strong>中文亂碼的問題</strong><br />
新版的 phpdoc 輸出的格式已經是 UTF-8 了,所以只要在目錄下增加一個 .htaccess 文件,然後內容為:<br />
<code>AddCharset UTF-8 .html</code><br />
<br />
<br />
參考文件:<br />
<a target="_blank" href="http://pkwbim-programming-note.blogspot.com/2008/01/phpdocumentor-0.html">多采多姿的程式筆記: phpDocumentor筆記 - 0 立即體驗</a><br />
<a target="_blank" href="http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_phpDocumentor.howto.pkg.html">phpDocumentor Tutorial</a><br />
<a target="_blank" href="http://luchuan.iteye.com/blog/954147">phpDocumentor学习记录</a>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0