2011年2月25日 星期五

Moving SQL NVarchar to ORACLE NVarchar2

之前用SSIS在做ORACLE與SQL間資料搬移時,最痛恨遇到NVarchar跟Unicode Code問題了。

明明是NVarchar(SQL)搬到NVarchar2(ORACLE),兩邊都Support Unicode,但SSIS都老會要求指定Data Flow Destination的Code Page,接著又會嚷著SQL中得到的Unicode不能直接轉成Non-Unicode,所以就得很可笑地在Nvarchar與NVarchar2兩個Unicode欄位中加上一個Data Conversion。如下圖:

不過,苦難還沒有結束... 如果很不幸地,NVarchar中還真的放了Unicode字元,則在轉換時,會出現以下的錯誤訊息。

Error: 0xC02020C5 at Data Flow Task Failure Sample, Data Conversion [543]: Data conversion failed while converting column "UnicodeField" (505) to column "UnicodeFieldMapping" (557). The conversion returned status value 4 and status text "Text was truncated or one or more characters had no match in the target code page.".
Error: 0xC020902A at Data Flow Task Failure Sample, Data Conversion [543]: The "output column "UnicodeFieldMapping" (557)" failed because truncation occurred, and the truncation row disposition on "output column "UnicodeFieldMapping" (557)" specifies failure on truncation. A truncation error occurred on the specified object of the specified component.

這問題讓我很困擾,不過因為遇到時都是做些一次性的資料搬移,所以我都很鄉愿地繞路解決(最愛用的一招是回去改用SQL 2000 DTS,很奇怪,用DTS搬資料時,幾乎不曾為Enocding傷過腦筋),未曾認真與它對決過。

最近同事想用SSIS來做重要的日常資料搬移,就卡在這個問題上,由於搬移是每天要跑的,繞路的成本就會高出許多,這回我總算被迫要收服這隻妖怪。東試西試之餘,忽然想到之前使用Query Express的經驗,Oracle的OLE DB Driver才能正確顯示Unicode,Microsft的OLE DB for Oracle反而不行,所以我試著把Data Flow Destination的OLE DB換成Oracle版。

美妙的事出現了!! 使用Oracle Provider for OLE DB後,連Data Conversion都不用了,直接對Unicode對Unicode,一次搞定。

看一下令人興奮的結果,SQL裡的六頭牛被搬到ORACLE裡了,NVarchar --> NVarchar2,萬牛奔騰的感覺豈是一個爽字可以形容,哈!!


source: http://blog.darkthread.net/post-2007-05-17-kb-ssis-moving-sql-nvarchar-to-oracle-nvarchar2.aspx

2011年2月19日 星期六

Google App Engine for Java下的URL編碼轉換問題


URL编码问题

此部分参考英文资料:

在HTTP客户端使用get方法通过URL向服务器发送参数里,由于URL里面只可以包含允许的字符(也称为合法字符),所以一旦参数里面存在非法字符,就必须通过某种手段对其进行合法化转换,在服务器端再将其转换回来,

在RFC1738:Uniform Resource Locators (URL) 规范中,指出URL只能包含AscII集中的一个子集中的字符,这个子集也称作AscII character-set,原文写道:

"...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."

实际上URL规范中,字符包括保留字符,非保留字符两种,RFC2396中定义了URL中的保留(reserved)字符为:


Reserved

reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |

"$" | ","

非保留字符为:

Unreserved

unreserved = alphanum | mark


mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"

实际上非保留字符就是AscII character-set,此集合之外的字符都被称为非法字符(invalid character)或不安全字符(unsafe character),这些字符都将被编码转换为合法字符(valid character)或叫安全字符(safe charactor),转换的动作在英文常表示为escape。

escape的方式如下规范中所述:

Escaped Encoding

An escaped octet is encoded as a character triplet, consisting of the

percent character "%" followed by the two hexadecimal digits

representing the octet code. For example, "%20" is the escaped

encoding for the US-ASCII space character.


escaped = "%" hex hex

hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |

"a" | "b" | "c" | "d" | "e" | "f"

转换时使用的字符集为ISO-8859-1也称为ISO-Latin或Latin-1,注意不是Unicode,这就引起了新的问题,对于不在ISO-Latin中的符号,就没有一个安全的途径进行编码,因为根据RFC2396(注意这是URI规范,但是对URL适用,因为URL是URI的子集,有兴趣的读者请查阅URL和URI之间的关系),URL里还无法指定自定义的字符集(比如UTF-8)。

虽然根据标准,在URL中我们无法使用非ISO-Latin字符集以外的字符,但是在现实中,为了解决实际问题,大家都有事实上的标准那就是Unicode编码,现行的为UTF-8,现在浏览器都支持UTF-8的URL编码转换,当然,这个时候的转换动作不再叫escape,而是称为URIEncode。另外,UTF-8与Latin-1是兼容的,相关的信息可参考:

PHP与Javascript相关的URIEncode操作请参见:http://blog.verymore.com/show-989-1.html

GWT的URL编码与解码

使用URL类中的静态方法URL.decode 和 URL.encode来进行。

java.lang.Object

com.google.gwt.http.client.URL

Method Summary

static java.lang.String

decode(java.lang.String encodedURL)

Returns a string where all URL escape sequences have been converted back to their original character representations.

static java.lang.String

decodeComponent(java.lang.String encodedURLComponent)

Returns a string where all URL component escape sequences have been converted back to their original character representations.

static java.lang.String

encode(java.lang.String decodedURL)

Returns a string where all characters that are not valid for a complete URL have been escaped.

static java.lang.String

encodeComponent(java.lang.String decodedURLComponent)

Returns a string where all characters that are not valid for a URL component have been escaped.

GAE4Java的编码与解码

实际上,由于写本文的初衷是作者在这个环境下开发程序时想理清这个问题,所以将服务器环境定位为GAE,实际上就是Java下的URL编码问题,可以参考:http://china.manufacturer.com/article/study_for_character_encoding_java.htm

Java中URI Encoding的相关类为URLEncoder,URLDecoder

示例:

1 String text = java.net.URLEncoder.encode("编码转换", "utf-8");

java.lang.Object
java.net.URLEncoder


Method Summary

static String

encode(String s, String enc)

使用指定的编码机制将字符串转换为 application/x-www-form-urlencoded 格式。


URLDecoder此处略去,同上。

【完】

source:
http://www.cnblogs.com/dengfanxin/archive/2009/04/16/GAE_UrlEncoding.html

2011年2月15日 星期二

房产地图google map的初步应用点滴.1)

以前的房产地图一直都是使用有道地图,虽然有道地图是很好,但是为了更好,还是决定使用google地图来重新开发^_^,下面是一个开发完毕的简单应用http://xf.house.163.com/gz/map/000B.html

1)整合Google Maps JavaScript API V3 与 Google Local Search API

Google Maps JavaScript API V3
地址 http://code.google.com/intl/zh-CN/apis/maps/documentation/javascript/

Google Maps JavaScript API V3 文档读起来真的是很清晰,各种demo也很齐全,并且论坛的拥有巨大的论坛支持,对比了一下Google Maps JavaScript API V3 和 V2 的版本,虽然第3版的 Google Maps API 看上去跟第2版挺相识,但在内在机制上有了较大的变化,尤其在对移动浏览器的支持上,专门针对iphone和android设备的开发。V2版本google已经宣布不再予以继续支持,所以还是选择了V3版本。

Google Local Search API
地址 http://code.google.com/intl/zh-CN/apis/maps/documentation/localsearch/index.html

上面的地址是目前Local Search的最新地址,但郁闷的是居然挂上了 Deprecated ,一样的文档也相当齐全,在应用之前需要先为你的域名申请一个API key,这个是注册地址http://code.google.com/intl/zh-CN/apis/maps/signup.html,很简单,按照提示很快就搞定了。


在整合Google Maps JavaScript API V3和Google Local Search API发现这两个版本是不兼容的,Local Search API实际上还是沿用了Maps V2的接口,为了解决这个问题,需要中间一个跳板使得两者兼容,所以选择了iframe,父页面使用Google Maps V3,子页面使用Local Search API,当需要应用到本地搜索时,父页面向子页面传递查询条件,子窗口应用Local Search API获得查询的result后返回给父页面,这样就形成一个跳板,避免了两者因为版本问题而产生的冲突,当然还有其他的办法,不过iframe应该是比较简单处理,下面是一个demo



父页面 : 使用的是Google Maps JavaScript API V3,http://maps.google.com/maps/api/js 网址指向 Javascript 文件所在的位置,该文件会载入使用第 3 版 Google Maps API 所需的全部符号和定义。

DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>
<title>Google AJAX Search API Sampletitle>
<style type="text/css">
@import url("http://www.google.com/uds/css/gsearch.css");
@import url("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
@import url("http://www.google.com/uds/css/gsearch.css");
@import url("http://www.google.com/uds/solutions/localsearch/gmlocalsearch.css");
style>
<script type="text/javascript" src="http://xf.house.163.com/product/js/jquery.js">script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false">script>
<script type="text/javascript">
var map;
var lat = 23.116193;
var lng = 113.374525;
var markersArray = [];
var windowArray = [];
function initialize() {
var mapDiv = document.getElementById('map-canvas');
map
= new google.maps.Map(mapDiv, {
center:
new google.maps.LatLng(lat,lng),
zoom:
15,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}

//删除叠加层
function deleteOverlays() {
if (markersArray) {
for (i in markersArray) {
markersArray[i].setMap(
null);
}
markersArray.length
= 0;
}
}

//关闭信息提示窗口
function closeWindows() {
if (windowArray) {
for (i in windowArray) {
windowArray[i].close();
}
}
}

function show(results){
parent.deleteOverlays();
windowArray.length
= 0;
for (var i = 0; results && i < results.length; i++) {
showOne(results[i]);
}
}
function showOne(result){
//console.debug(result.title+","+result.lat+":" + result.lng +","+result.streetAddress+","+result.city+","+result.url);
var infowindow = new google.maps.InfoWindow({
content: result.html
});
var marker = new google.maps.Marker({
position:
new google.maps.LatLng(result.lat,result.lng),
map: map
});
markersArray.push(marker);
windowArray.push(infowindow);
google.maps.event.addListener(marker, 'click',
function() {
closeWindows();
infowindow.open(map,marker);
});
}
function searchMap(){
var keyWord = document.getElementById("keyWord").value;
mapIframe.window.loadMap(
23.116193,113.374525,keyWord);
}
google.maps.event.addDomListener(window, 'load', initialize);
script>
head>
<body style="">
<div id="map-canvas" style="width: 600px; height: 500px">div>
<input type="text" name="keyWord" id="keyWord"/>
<input type="button" onclick="searchMap();" value="查询" id="btn"/>

<iframe name="mapIframe" id="mapIframe" style="display:none" src="local.html">iframe>
body>
html>

子页面:http://www.google.com/jsapi?key 需要在google进行申请与域名绑定

DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=GBK"/>

<script src="http://www.google.com/jsapi?key=ABQIAAAAtV_DTJOYJT-9cvTO-5KJ2BSnjw5qeDlzCnItJoREFggHbBwu_RQBEyFqvq_vMlzqsS4afIB8ZIvMkw" type="text/javascript">script>
<script type="text/javascript">
google.load('search', '
1');
google.load('maps', '
2');

function loadMap(lat,lng,keyWord) {
var point = new GLatLng(lat,lng);
searchMap(point,keyWord);
}

function searchMap(point,keyWord){
var searcher = new google.search.LocalSearch();
searcher.setCenterPoint(point);
searcher.setResultSetSize(
8);
//searcher.setRestriction(google.search.Search.RESTRICT_TYPE, google.search.LocalSearch.TYPE_KMLONLY_RESULTS)
searcher.setSearchCompleteCallback(this, function() {
parent.MapApi.showSearch_Markers(searcher.results,keyWord);
});
searcher.execute(keyWord);
}
script>
head>
<body>body>
html>

摘录几个常用的Local Search API Reference

new google.search.LocalSearch() : 创建了一个LocalSearch的Service

searcher.setCenterPoint(point) : 它接受单一变量,该变量可以是字符串、google.maps.Map2 或google.maps.LatLng。如果是字符串,会尝试将字符串解析为 google.maps.LatLng

searcher.setResultSetSize(8) : 调用此方法以选择由每个搜索器返回的结果数

searcher.setRestriction() : 设置搜索结构类型

searcher.setSearchCompleteCallback() : 此方法用于注册对象和方法以通知搜索完成。应用程序可以通过使用 opt_arguments之后随意传入环境参数

searcher.execute(keyWord) : 调用此方法以开始新的搜索 

第一步解决了map和local search的版本冲突后,下面可以进行全部的开发,Google Maps JavaScript API提供的UI,EVENT相关接口非常之多,但不一定就能直接适用我们的需求,还需要使用继承基类MVCObject,OverlayView等继续封装。