tag:blogger.com,1999:blog-59465307047421309702024-03-06T16:20:07.273+08:00Jax 的工作紀錄除了在整理學習上的經驗,同時也能幫助其他需要的人Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.comBlogger132125tag: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-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-87252133296736508052022-09-08T13:39:00.005+08:002022-09-08T14:31:26.385+08:00架構解釋<p>以前在專案開發時對分層架構所定下的原則,去避免不必要的地雷,以及每一層的要處裡的職權。</p>
<p>我會考慮分層架構,是希望提高系統的嚴謹度,以及 Method 的共用性,所以 Dao 層級就要避免功能導向,不然就是把單頁的程式拆分到多個層去而已。</p>
<p> </p>
<h3>DomainModel / ViewModel</h3>
<ul>
<li>這三類都屬於 <a href="https://en.wikipedia.org/wiki/Plain_Old_CLR_Object" target="_blank">POCO</a> 類型的物件,單純的資料載體,不允許有動作的 method,不可以外部取資料</li>
<li>相同資料的欄位命名必須一致,反例: ProjectId, Pid, pid, PID, p_id</li>
<li>有欄位就要有資料,明明有欄位定義卻不從 DB 取資料,這會造成不必要的雷</li>
</ul>
<p> </p>
<h3>DomainModel</h3>
<ul>
<li>欄位定義可與 DB 一致</li>
<li>將 DB 的資料進行彙整,成為完整的資料體</li>
</ul>
<p> </p>
<h3>ViewModel</h3>
<p>欄位定義與 View 的表單(Form)一致,與 DomainModel 可能很相似,但有些欄位只會用在表單上,所以 DomainModel 不適合用在表單 Binding 上</p>
<p>例如:</p>
<ul>
<li>同意上述條款</li>
<li>舊密碼, 新密碼, 確認密碼</li>
</ul>
<p> </p>
<h3>Dao</h3>
<ul>
<li>回傳 DomainModel</li>
<li>定義單純的 BD 操作 List, GetById, Save, Insert, Update</li>
<li>與 ORM 不同,是進一步將資料操作簡化</li>
<li>保證 Method 的通用性,避免功能導向,例如: 有一個 Method 是專門為了A畫面功能而存在的</li>
</ul>
<p> </p>
<h3>Service</h3>
<ul>
<li>回傳 DomainModel</li>
<li>驗證商業邏輯,如必要資料欄位,數值範圍等...</li>
<li>調用一個或多個 Dao 來完成商業邏輯</li>
<li>處理 DB 交易,來協調多個 Dao 的調用</li>
</ul>
<p> </p>
<h3>Controller</h3>
<ul>
<li>處理 DomainModel 到 ViewModel 的轉換</li>
<li>調用 Service 進行 DomainModel 的資料處理</li>
<li>調配 Responses 的結果 Html, Json, PDF ...</li>
<li>驗證資料類型的正確,數值﹑日期</li>
<li>負責 Access 的權限阻擋</li>
</ul>
<p> </p>
<h3>View</h3>
<ul>
<li>View 是被動的,不能存取任何 Controller / Service / Dao</li>
<li>負責資料呈現及格式化,如 日期﹑金額 ...</li>
<li>Ajax 只能對 Controller 調用</li>
</ul>
<p> </p>
<h3>附註</h3>
<ol>
<li>同一層之間不可以互相參考,這容易發生循環參考,例如:
<ul>
<li>Controller 呼叫 Controller</li>
<li>Service 呼叫 Service</li>
<li>Dao 呼叫 Dao</li>
</ul>
</li>
<li>同一層之間有相同邏輯可以抽離到 Support 類<br/> </li>
<li>建議定義命名規範,讓每一個人寫出來的程式像是同一個人寫的,好處是降低支援或接手的人的困難度<br/> </li>
<li>任何第三方的 API 都需要包裝,隔離直接相依的問題,而且可以單獨測試<br/> </li>
</ol>
<p> </p>
<h3>架構關係全貌</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVkwcFPiMgYAI77ojQ-7uiud0enzdxVAexakLwozTveWuPeCfjXD5ABdCw6a1r1Xv1rWD8oM5HLET8aaukooy0xSfVK1skfASa4tPVjdEHdigEa20J7nO5FpdYBH_JpNv6169QIKlZGHNE8tIRoKS4KzzQ1_9ghgsrEu1V82nOZ_aKlL5U_DsPjmATGw/s698/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BA.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVkwcFPiMgYAI77ojQ-7uiud0enzdxVAexakLwozTveWuPeCfjXD5ABdCw6a1r1Xv1rWD8oM5HLET8aaukooy0xSfVK1skfASa4tPVjdEHdigEa20J7nO5FpdYBH_JpNv6169QIKlZGHNE8tIRoKS4KzzQ1_9ghgsrEu1V82nOZ_aKlL5U_DsPjmATGw/s600/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BA.png"/></a>
<p> </p>
<h3>Model 傳遞的關係</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitPjeZp31dPOetYZOsq06OnuPtNdTKaiek3PHNsmBmQpgTP7Ik9agnwDVoL8lRme5mIV59Ct4jtfuSKVbQY9TVjHUX2qx0ZFeJCw0-aOCt0rI0qJ-hVFNKG1RrhHhC73BTGSMU9XqfKPaLK0f5eKEUuvSXBVoKC2KzGuKSKdFc5RH_8cj3wCsZ2M5oqQ/s528/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BB.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitPjeZp31dPOetYZOsq06OnuPtNdTKaiek3PHNsmBmQpgTP7Ik9agnwDVoL8lRme5mIV59Ct4jtfuSKVbQY9TVjHUX2qx0ZFeJCw0-aOCt0rI0qJ-hVFNKG1RrhHhC73BTGSMU9XqfKPaLK0f5eKEUuvSXBVoKC2KzGuKSKdFc5RH_8cj3wCsZ2M5oqQ/s600/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BB.png"/></a>
<p> </p>
<h3>用 Interface 隔離實作</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0AU8ww03wJDlVHcK9J6YcsM8g4cfxYNE31p8IXYg9F90pcvNb8AMbldXM5U1HCEwoERTPSKIQySFBurA7aJGJkS7x9DS8b1k3jCl1vYaHl3W6JeQ9LmshMkyvXPHsiNAW94clEiUJtA1XNv1K2vNAcpgsXTiZfb1r98yjt_sH9aGA_JosNsxwKABJ1g/s586/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BC.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0AU8ww03wJDlVHcK9J6YcsM8g4cfxYNE31p8IXYg9F90pcvNb8AMbldXM5U1HCEwoERTPSKIQySFBurA7aJGJkS7x9DS8b1k3jCl1vYaHl3W6JeQ9LmshMkyvXPHsiNAW94clEiUJtA1XNv1K2vNAcpgsXTiZfb1r98yjt_sH9aGA_JosNsxwKABJ1g/s600/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BC.png"/></a>
<p> </p>
<h3>Web Api 的呼叫關係</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrenh3MuEHl1cjacIDy0VVFUBbxczmwdmEEc61TuGbDTc2C56bqjM3puRj1q9iC32yK-Dt_yKI0xje0Gw7Cu9tn4KI_Ddv4tv_uAqnjVEJ09qDUkwPm6q1w1YTtEf_kL_G8AzD6bK3IOgwnvikHr1_7SOZnZU4uRhtpTBdvNtWx3ybYeTN-1hp4ZIPtg/s430/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BD.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrenh3MuEHl1cjacIDy0VVFUBbxczmwdmEEc61TuGbDTc2C56bqjM3puRj1q9iC32yK-Dt_yKI0xje0Gw7Cu9tn4KI_Ddv4tv_uAqnjVEJ09qDUkwPm6q1w1YTtEf_kL_G8AzD6bK3IOgwnvikHr1_7SOZnZU4uRhtpTBdvNtWx3ybYeTN-1hp4ZIPtg/s600/%E6%9E%B6%E6%A7%8B%E8%A7%A3%E9%87%8BD.png"/></a>
<p> </p>
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-57180131894898724472021-10-16T12:50:00.005+08:002023-02-25T18:15:30.082+08:00週期性執行的子執行緒範本<p>關於週期性執行的子執行緒有幾個要點:</p>
<ul>
<li>單次 Sleep 的時間不要太久,會影響程式的關閉</li>
<li>不可以用 SpinWait 來做程式暫停,要用 Sleep 來暫停,這樣才會釋放 CPU</li>
<li>Error log 要注意會重複出現相同的 error</li>
<li>有排除重複 error 時,要記得加上[錯誤解除]的 log,這樣才能知道程式是否有回到正常執行</li>
<li>要執行的程式邏輯移到一個 method 裡,這樣可以避免 return 造成的迴圈中斷,也能分離邏輯的關注點</li>
</ul>
<br/>
<br/>
<h3>週期小於 10 秒的範本</h3>
<pre class="cs" name="code">
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleMSec = 1000;
private bool _runFlag = false;
private string _prevError;
public void Start()
{
if (_runFlag) { return; }
_runFlag = true;
var thread = new Thread(() =>
{
while (_runFlag)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(_cycleMSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
});
thread.Start();
}
public void Stop()
{
_runFlag = false;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
</pre>
<br/>
<br/>
<h3>週期大於 10 秒的範本</h3>
<pre class="cs" name="code">
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleSec = 30;
private bool _runFlag = false;
private string _prevError;
private DateTime _nextTime = DateTime.Now;
public void Start()
{
if (_runFlag) { return; }
_runFlag = true;
var thread = new Thread(() =>
{
while (_runFlag)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(1000);
/* 檢查是否符合執行時間 */
if (_nextTime > DateTime.Now) { continue; }
/* 更新下一次的執行時間 */
_nextTime = DateTime.Now.AddSeconds(_cycleSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
});
thread.Start();
}
public void Stop()
{
_runFlag = false;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
</pre>
<br/>
<br/>
<h3>停啟頻繁的範本</h3>
<pre class="cs" name="code">
public enum CycleStatus
{
Stop,
Start,
Stoping,
}
public CycleStatus RunStatus { get; private set; } = CycleStatus.Stop;
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
private int _cycleMSec = 1000;
private string _prevError;
public void Start()
{
if (RunStatus != CycleStatus.Stop)
{ throw new Exception("程序還在進行中"); }
RunStatus = CycleStatus.Start;
var thread = new Thread(() =>
{
while (RunStatus == CycleStatus.Start)
{
/* 先睡可以避免在程式啟動時過於忙碌 */
Thread.Sleep(_cycleMSec);
try
{
/* 要執行的程式邏輯 */
cycleHandler();
if (_prevError != null) { _log.Info("錯誤結束"); }
_prevError = null;
}
catch (Exception ex)
{
/* 避免相同的錯誤一直被記錄 */
if (_prevError == ex.Message) { continue; }
_prevError = ex.Message;
_log.Fatal(ex, "執行錯誤");
}
}
RunStatus = CycleStatus.Stop;
});
thread.Start();
}
public void Stop()
{
if (RunStatus == CycleStatus.Stop)
{ throw new Exception("程序已經停止"); }
if (RunStatus == CycleStatus.Stoping)
{ throw new Exception("程序正在停止"); }
RunStatus = CycleStatus.Stoping;
}
private void cycleHandler()
{
// 主要的邏輯程式寫在這裡
}
</pre>
<br/>
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-73689069923592396712020-07-06T13:18:00.004+08:002023-02-25T18:26:32.160+08:00C# MVC Cassette 隔離區快取找不到的錯誤有使用 <a href="http://getcassette.net/" target="_blank">Cassette</a> 的專案,在發布站台之後網頁開起來卻發生了 JS 跟 CSS 全部掉光,查看錯誤訊息時發現 <a href="http://getcassette.net/" target="_blank">Cassette</a> 抓不到在隔離區的快取。<br />
<br />
原因是當 JS 跟 CSS 有更新時,Cassette 會重新產生快取的 key,卻沒有產生隔離區的快取檔案,造成抓不到快取的問題,IIS pool 重啟也無效,Cassette 的管理畫面也進不去。<br />
<br />
解決辦法就是呼叫 <code>Bundles.RebuildCache()</code>,最好方式就是在 Global.asax.cs 增加自動處裡。<br />
<br />
<pre class="cs" name="code">protected void Application_Error(object sender, EventArgs e)
{
/* 重建 Cassette 綑綁 */
var ex = Server.GetLastError() as System.IO.FileNotFoundException;
if (ex != null && ex.StackTrace.Contains("Cassette."))
{ Bundles.RebuildCache(); }
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-87759850099603716812019-07-19T16:46:00.001+08:002023-02-25T21:26:28.262+08:00WCF IP Filter<pre class="xml" name="code"><!-- Web.config -->
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="ipFilter" type="XXX.XXX.IpFilterElement, XXX.XXX" />
</behaviorExtensions>
</extensions>
<!-- .... -->
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<ipFilter allow="192.168.1.0/24, 127.0.0.1" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</pre><br />
<pre class="cs" name="code">using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Security.Authentication;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using JustWin.API.Extensions;
public class IpFilterElement : BehaviorExtensionElement
{
[ConfigurationProperty("allow", IsRequired = true)]
public virtual string Allow
{
get { return this["allow"] as string; }
set { this["allow"] = value; }
}
public override Type BehaviorType
{
get { return typeof(IpFilterBehaviour); }
}
protected override object CreateBehavior()
{
return new IpFilterBehaviour(Allow);
}
}
public class IpFilterBehaviour : IDispatchMessageInspector, IServiceBehavior
{
private readonly List<IPAddressRange> _allowList;
public IpFilterBehaviour(string allow)
{
_allowList = allow.Split(',').Select(x => new IPAddressRange(x)).ToList();
}
void IServiceBehavior.Validate(ServiceDescription service, ServiceHostBase host)
{
}
void IServiceBehavior.AddBindingParameters(ServiceDescription service, ServiceHostBase host, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription service, ServiceHostBase host)
{
foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers)
foreach (EndpointDispatcher endpoint in dispatcher.Endpoints)
{
endpoint.DispatchRuntime.MessageInspectors.Add(this);
}
}
object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
var remoteEndpoint = request.Properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
var address = IPAddress.Parse(remoteEndpoint.Address);
if(_allowList.Any(x => x.IsMatch(address))) { return null; }
request = null;
return new AuthenticationException($"IP address ({remoteEndpoint.Address}) is not allowed.");
}
void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
{
var ex = correlationState as Exception;
if (ex == null) { return; }
MessageFault messageFault = MessageFault.CreateFault(
new FaultCode("Sender"),
new FaultReason(ex.Message),
ex,
new NetDataContractSerializer()
);
reply = Message.CreateMessage(reply.Version, messageFault, null);
}
}
public class IPAddressRange
{
private readonly byte[] _rangeAddress;
private readonly byte[] _rangeMask;
public IPAddressRange(string ipAndMask)
{
string[] split = (ipAndMask + "/128").Split('/');
var ip = IPAddress.Parse(split[0].Trim());
int maskLength = int.Parse(split[1].Trim());
if (ip.AddressFamily == AddressFamily.InterNetwork) { maskLength += 96; }
_rangeMask = createMask(maskLength);
_rangeAddress = ip.MapToIPv6().GetAddressBytes()
.Select((x, i) => x & _rangeMask[i])
.Select(x => (byte)x)
.ToArray();
}
public bool IsMatch(IPAddress ip)
{
byte[] address = ip.MapToIPv6().GetAddressBytes();
for (int i = 0; i < 16; i++)
{
if ((address[i] & _rangeMask[i]) != _rangeAddress[i]) { return false; }
}
return true;
}
private byte[] createMask(int length)
{
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); }
}
return mask;
}
}
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-69820948975018862712018-05-12T23:58:00.000+08:002018-05-12T23:58:53.369+08:00Windows Server 磁碟清理<br />
磁碟清理<br />
<code>DISM.exe /online /Cleanup-Image /StartComponentCleanup</code><br />
<br />
清理系統 Service Pack 備份檔案<br />
<code>DISM.exe /Online /Cleanup-Image /SPSuperseded</code>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-44066777843784532492018-05-12T23:53:00.000+08:002018-05-12T23:53:41.178+08:00Visual Studio 快捷鍵<table class="table_list"><tr><td>Ctrl + L</td><td>刪除行</td></tr>
<tr><td>Ctrl + X</td><td>剪下行(游標不選取文字)</td></tr>
<tr><td>Ctrl + C</td><td>複製行(游標不選取文字)</td></tr>
<tr><td>Ctrl + J</td><td>呼叫出類別成員</td></tr>
<tr><td>Ctrl + K,C</td><td>註解選取範圍</td></tr>
<tr><td>Ctrl + K,U</td><td>取消註解選取範圍</td></tr>
<tr><td>Ctrl + R,R</td><td>重新命名變數</td></tr>
<tr><td>F2</td><td>重新命名變數</td></tr>
<tr><td></td><td></td></tr>
<tr><td>Ctrl + Enter</td><td>上方插入一列</td></tr>
<tr><td>Ctrl + Shift + Enter</td><td>下方插入一列</td></tr>
<tr><td>Ctrl + 减號</td><td>回到上次游標位置</td></tr>
<tr><td>CTRL + SHIFT + 减號</td><td>反之</td></tr>
<tr><td>Ctrl + F3</td><td>找當前選取</td></tr>
<tr><td>F3</td><td>找下一個</td></tr>
<tr><td>Shift + F3</td><td>找上一個</td></tr>
<tr><td>Ctrl + F</td><td>尋找文字</td></tr>
<tr><td>Ctrl + Shift + F</td><td>跨檔案尋找文字</td></tr>
<tr><td>Ctrl + H</td><td>取代文字</td></tr>
<tr><td>Ctrl + Shift + H</td><td>跨檔案取代文字</td></tr>
<tr><td>Ctrl + J</td><td>顯示物件的成員清單</td></tr>
<tr><td>Ctrl + K, D</td><td>格式化文件</td></tr>
<tr><td>Ctrl + K, F</td><td>格式化選取範圍</td></tr>
<tr><td>Ctrl + E, S</td><td>顯示空白字元</td></tr>
<tr><td>Ctrl + E, \</td><td>刪除行尾空白</td></tr>
<tr><td>Ctrl + Alt + ]</td><td>對齊等號</td></tr>
<tr><td>Ctrl + ]</td><td>切換至對應刮號</td></tr>
<tr><td></td><td></td></tr>
<tr><td>F12</td><td>轉至定義</td></tr>
<tr><td>Ctrl + F12</td><td>轉至實做</td></tr>
<tr><td>Alt + F12</td><td>查看定義</td></tr>
<tr><td>F5</td><td>偵錯建置</td></tr>
<tr><td>Ctrl + F5</td><td>建置</td></tr>
<tr><td>Ctrl + U</td><td>小寫</td></tr>
<tr><td>Ctrl + Shift + U</td><td>大寫</td></tr>
<tr><td>Alt + 上</td><td>選取行上移</td></tr>
<tr><td>Alt + 下</td><td>選取行下移</td></tr>
<tr><td>Ctrl + K, K</td><td>切換書籤</td></tr>
<tr><td>Ctrl + .</td><td>開啟智慧標籤選單</td></tr>
<tr><td>Shift + Alt + F10</td><td>開啟智慧標籤選單</td></tr>
</table>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-55480413068311281562017-09-01T11:27:00.000+08:002017-09-01T11:29:22.939+08:00SQL Server Management Studio 資料表設計模式顯示欄位描述 <br />
開啟登錄檔編輯器 regedit.exe <br />
搜尋 SSVPropViewColumnsSQL70 及 SSVPropViewColumnsSQL80 <br />
將值從 1,2,6; 改為 1,2,6,17;<br />
<br />
各個屬性欄位代號:<br />
<pre>1: Column Name
2: Data Type
3: Length
4: Precision
5: Scale
6: Allow Nulls
7: Default Value
8: Identity
9: Identity Seed
10: Identity Increment
11: Row GUID
12: Nullable
13: Condensed Type
14: Not for Replication
15: Formula
16: Collation
17: Description
</pre><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicoX6JfbJq4x4cZWbkQRd7rZ-nr7C8VOqy9n8g-pdaSbHNejWwl1A4D4xTLJLRGayl5vaq0HhwZpO698-6sn4dh7YnK_rp0e2csOuZcCrQ-qMlxJjhPqWTWWjO86tpkCzJr1e7Ns1nc213/s1600/MWSnap124.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicoX6JfbJq4x4cZWbkQRd7rZ-nr7C8VOqy9n8g-pdaSbHNejWwl1A4D4xTLJLRGayl5vaq0HhwZpO698-6sn4dh7YnK_rp0e2csOuZcCrQ-qMlxJjhPqWTWWjO86tpkCzJr1e7Ns1nc213/s550/MWSnap124.png" /></a><br />
<br />
<a href="https://4.bp.blogspot.com/-o5BU68BCQ18/WajTPWv4ttI/AAAAAAAAN8I/ffwgywSoVsYUIfydV0sTFuhQd4XYY3VuACLcBGAs/s1600/MWSnap125.png"><img src="https://4.bp.blogspot.com/-o5BU68BCQ18/WajTPWv4ttI/AAAAAAAAN8I/ffwgywSoVsYUIfydV0sTFuhQd4XYY3VuACLcBGAs/s550/MWSnap125.png" /></a>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-5254769756673397792016-04-07T12:07:00.001+08:002023-02-25T21:29:35.395+08:00C# MVC + Cassette<a href="http://getcassette.net/" target="_blank">Cassette</a> 與 MVC 預設的 Bundle 最大的差異就是會自動轉換 CSS 的圖片網址。缺點就是開發時 F5 啟動專案會變慢。<br />
<br />
<br />
<h3>NuGet 安裝</h3><ul><li>Cassette.Aspnet</li>
<li>Cassette.Views</li>
<li>Cassette</li>
</ul><br />
<br />
<h3>Web.config</h3><br />
基本上安裝完就會自動配置以下設定,但可以在確認一下。<br />
<br />
<pre class="xml" name="code"><configuration>
<configSections>
<section name="cassette"
type="Cassette.CassetteConfigurationSection, Cassette"
requirePermission="false"
/>
</configSections>
<system.web>
<pages>
<namespaces>
<add namespace="Cassette.Views" />
</namespaces>
</pages>
<httpModules>
<add name="CassetteHttpModule"
type="Cassette.Aspnet.CassetteHttpModule, Cassette.Aspnet"
/>
</httpModules>
<httpHandlers>
<!-- 用來處理綑綁打包的處理器 -->
<add path="cassette.axd"
verb="*"
type="Cassette.Aspnet.CassetteHttpHandler, Cassette.Aspnet"
/>
</httpHandlers>
</system.web>
<system.webServer>
<!-- 保留 httpHandlers(IIS6) 及 handlers(IIS7) 需要關閉驗證 -->
<validation validateIntegratedModeConfiguration="false" />
<modules>
<add name="CassetteHttpModule"
type="Cassette.Aspnet.CassetteHttpModule, Cassette.Aspnet"
/>
</modules>
<handlers>
<!-- 用來處理綑綁打包的處理器 -->
<add name="CassetteHttpHandler"
path="cassette.axd"
verb="*"
allowPathInfo="true"
preCondition="integratedMode"
type="Cassette.Aspnet.CassetteHttpHandler, Cassette.Aspnet"
/>
</handlers>
</system.webServer>
<!-- For configuration options: http://getcassette.net/documentation/v2/web-config -->
<cassette rewriteHtml="false" />
</configuration>
</pre><br />
<br />
<br />
<h3>Views/Web.config</h3><br />
增加給 cshtml 用的 namespace<br />
<br />
<pre class="xml" name="code"><configuration>
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="Cassette.Views" />
</namespaces>
</pages>
</system.web.webPages.razor>
</configuration>
</pre><br />
<br />
<br />
<h3>CassetteConfiguration.cs</h3><br />
<pre class="cs" name="code">public class CassetteBundleConfiguration : IConfiguration<BundleCollection>
{
public void Configure(BundleCollection bundles)
{
bundles.AddPerIndividualFile<StylesheetBundle>("Content");
bundles.AddPerIndividualFile<ScriptBundle>("Scripts");
bundles.Add<StylesheetBundle>("Styles/Bundles", new string[]
{
"~/Scripts/bootstrap/css/bootstrap.css",
"~/Scripts/bootstrap/css/bootstrap-theme.css",
//...
});
bundles.Add<ScriptBundle>("Scripts/Bundles", new string[]
{
"~/Scripts/jquery/jquery-1.12.2.js",
"~/Scripts/jquery.validate/jquery.validate-1.12.0.js",
//...
});
}
}
</pre><br />
<br />
<br />
<h3>_Layout.cshtml</h3><br />
<pre class="xml" name="code"><!DOCTYPE html>
@{
Bundles.Reference("Styles/Bundles");
Bundles.Reference("Scripts/Bundles");
}
<html>
<head>
@Bundles.RenderStylesheets()
</head>
<body id="DialogLayout">
@Bundles.RenderScripts()
</body>
</html>
</pre><br />
<br />
<br />
<h3>Release Mode</h3><br />
當 Web.config 的 compilation debug="false" 就會壓縮綑綁。 <br />
<br />
<pre class="xml" name="code"><compilation debug="false" targetFramework="4.5" />
</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-39181220147476341712015-03-10T15:18:00.000+08:002015-03-13T09:04:50.695+08:00[Java] 產生驗證碼圖片<pre class="java" name="code">import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Random;
import javax.imageio.ImageIO;
public class TestCaptchaImage {
public static void main(String[] args) throws Exception {
String captcha = "09875";
int width = 55;
int height = 20;
Color fontColor = new Color(36, 85, 92); /*文字顏色*/
Color lineColor = new Color(65, 161, 175); /*線條顏色*/
Color bgColor = new Color(208, 226, 229); /*底色*/
Random random = new Random();
random.setSeed(System.currentTimeMillis());
BufferedImage image = new BufferedImage(
width, height, BufferedImage.TYPE_INT_RGB
);
Graphics g = image.getGraphics();
/* 底色 */
g.setColor(bgColor);
g.fillRect(0, 0, width, height);
/* 畫線 */
g.setColor(lineColor);
for (int i=0; i < 20; i++) {
g.drawLine(
random.nextInt(width), 0,
random.nextInt(width), height
);
}
/* 畫出文字 */
g.setFont(new Font("Atlantic Inline", Font.BOLD, 20));
g.setColor(fontColor);
g.drawString(captcha, 0, 18);
/* 畫線 */
g.setColor(lineColor);
for (int i=0; i < 4; i++) {
g.drawLine(
0, random.nextInt(height),
width, random.nextInt(height)
);
}
g.dispose();
ImageIO.write(image, "png", new File("captcha_image.png"));
}
}
</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-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-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-44160072254927015452015-03-04T11:27:00.003+08:002015-03-04T11:27:43.734+08:00[Java] 取得本地端 IP 與 MAC<pre class="java:nogutter:nocontrols" name="code">import java.net.InetAddress;
import java.net.NetworkInterface;
public class TestInetAddress {
public static void main(String[] args) throws Exception {
InetAddress ip = InetAddress.getLocalHost();
System.out.println("Current IP address : " + ip.getHostAddress());
// Current IP address : 192.168.0.109
System.out.println(ip.getCanonicalHostName());
// 192.168.0.109
System.out.println(ip.getHostName());
// jaxhu-PC
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%s%02X", (i > 0 ? "-" : ""), mac[i]));
}
System.out.println("Current MAC address : " + sb.toString());
// Current MAC address : 38-2C-4A-B4-C3-24
System.out.println(network.getDisplayName());
// Realtek PCIe GBE Family Controller
System.out.println(network.getName());
// eth3
}
}
</pre><br />
參考自:<a href="http://www.mkyong.com/java/how-to-get-mac-address-in-java/" target="_blank">How to get MAC address in Java : Mkyong</a><br />
Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-43492161064296939902015-03-04T11:20:00.000+08:002015-03-04T11:20:06.120+08:00[Java] 執行 shell command<pre class="java:nogutter:nocontrols" name="code">Process p = Runtime.getRuntime().exec("ping -n 3 google.com");
p.waitFor();
Scanner sc = new Scanner(p.getInputStream(), "MS950");
String output = sc.useDelimiter("\\Z").next();
sc.close();
System.out.println("exitValue: " + p.exitValue());
System.out.println(output);
</pre><br />
Output:<br />
<pre class="none:nogutter:nocontrols" name="code">exitValue: 0
Ping google.com [173.194.72.138] (使用 32 位元組的資料):
回覆自 173.194.72.138: 位元組=32 時間=21ms TTL=48
回覆自 173.194.72.138: 位元組=32 時間=20ms TTL=48
回覆自 173.194.72.138: 位元組=32 時間=18ms TTL=48
173.194.72.138 的 Ping 統計資料:
封包: 已傳送 = 3,已收到 = 3, 已遺失 = 0 (0% 遺失),
大約的來回時間 (毫秒):
最小值 = 18ms,最大值 = 21ms,平均 = 19ms
</pre>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-39540915183529208392015-02-26T09:41:00.000+08:002015-02-26T09:45:24.993+08:00[SVN] 取得最新的版號日期命令列指令:<br />
<code>svn info</code><br />
<br />
<pre class="none:nocontrols" name="code">Path: .
URL: https://xxxxxxxxxxxxxxxxxxxx
Repository Root: https://xxxxxxxxxxxxxxxxxxxx
Repository UUID: 7be9c518-46a6-4cff-bfa7-8a37a304b21d
Revision: 78
Node Kind: directory
Schedule: normal
Last Changed Author: weskerjax
Last Changed Rev: 78
Last Changed Date: 2015-01-09 23:48:14 +0800 (週五, 09 一月 2015)
</pre><br />
<br />
輸出 XML 格式:<br />
<code>svn info --xml</code><br />
<br />
<pre class="xml:nocontrols" name="code"><?xml version="1.0"?>
<info>
<entry kind="dir" path="." revision="78">
<url>https://xxxxxxxxxxxxxxxxxxxxxx</url>
<repository>
<root>https://xxxxxxxxxxxxxxxxxxxxxx</root>
<uuid>7be9c518-46a6-4cff-bfa7-8a37a304b21d</uuid>
</repository>
<wc-info>
<schedule>normal</schedule>
<depth>infinity</depth>
</wc-info>
<commit revision="78">
<author>weskerjax</author>
<date>2015-01-09T15:48:14.049424Z</date>
</commit>
</entry>
</info>
</pre>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag:blogger.com,1999:blog-5946530704742130970.post-91477692629219653452015-02-24T21:13:00.000+08:002015-02-26T09:45:24.999+08:00[Git] 取得最新的版號日期<pre class="sh:nogutter:nocontrols" name="code">git log -1 --date=short --format='%cd %h'
# 2015-02-13 e396510
git log -1 --date=short --format=%cd
# 2015-02-13
git log -1 --format=%h
# e396510
</pre><br />
<b>-1 </b><br />
只顯示第一筆 (筆數)<br />
<br />
<b>--date=short</b><br />
短的日期格式<br />
<br />
<b>--format=%cd</b><br />
commit date <br />
<br />
<b>--format=%h</b><br />
短版的 commit hash <br />
<br />
參考資料:<a href="https://www.kernel.org/pub/software/scm/git/docs/git-log.html" target="_blank">git-log(1) Manual Page </a>Jax Huhttp://www.blogger.com/profile/01953021685585893658noreply@blogger.com0tag: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.com0