jQuery ajax在GBK编码下表单提交终极解决方案(非二次编码方法) - JavaScript - web - ITeye论坛
http://www.open-lib.com/Forum/Read_69_1.action
前言:
当jquery ajax在utf-8编码下(页面utf-8,接收utf-8),无任何问题。可以正常post、get,处理页面直接获取正确的内容。
但在以下情况下:
GBK -> AJAX POST ->GBK
UTF-8 -> AJAX POST ->GBK
后台代码无法获取正确的内容,通常表现为获取到奇怪字符、问号。
经典解决方法:
1:发送页面、接收页面均采用UTF-8编码。
2:发送页面在调用ajax post方法之前,将含有中文内容的input用encodeURIComponent编码一次,而接收页面则调用解码方法( 如:java.net.urldecoder.decode("接收到内容","utf-8") )。
其中,第一种方法无疑是最简单、最直接,但往往不符合实际,因为很多项目并不是使用utf-8编码,例如国内大部分使用gbk编码,也不可能为了解决这样一个问题,而将整个项目转换为utf-8编码,成本太大,风险太高。
第二方法,是现在最多人使用的方法,俗称二次编码,为什么叫二次编码,等下会解释。客户端编码两次,服务端解码两次。但这种方法不好的地方,就是前台手动编码一次,后台再手动解码一次,稍不留神就会忘记,而且代码掺和前台逻辑。
交互过程:
当我们使用表单按照传统方式post提交时候(非AJAX提交),浏览器会根据当前页面编码,encode一次,然后发送到服务端,服务端接收到表单,会自动dencode一次,通常这个过程是对程序是透明的,因此加上手动编码、解码,就变成上面所说的二次编码。
但当我们使用AJAX方式提交时候,浏览器并不会自动替我们encode,因此在jquery中有这样的一段代码:
- ajax: function( s ) {
- // Extend the settings, but re-extend 's' so that it can be
- // checked again later (in the test suite, specifically)
- s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
- var jsonp, jsre = /=?(&|$)/g, status, data,
- type = s.type.toUpperCase();
- // convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" )
- s.data = jQuery.param(s.data);
- ........
- }
以上是jquery的ajax方法的代码片段,下面是正常调用jquery ajax post的代码:
- $.ajax({
- url: ajaxurl,
- type: 'POST',
- dataType: 'html',
- timeout: 20000,//超时时间设定
- data:para,//参数设置
- success: function(html){
- }
- });
通过上面代码可以知道,当设置了data时候,jquery内部会调用jQuery.param方法对参数encode(执行本应浏览器处理的encode)。
- jQuery.param=function( a ) {
- var s = [ ];
- function add( key, value ){
- s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
- };
- // If an array was passed in, assume that it is an array
- // of form elements
- if ( jQuery.isArray(a) || a.jquery )
- // Serialize the form elements
- jQuery.each( a, function(){
- add( this.name, this.value );
- });
- // Otherwise, assume that it's an object of key/value pairs
- else
- // Serialize the key/values
- for ( var j in a )
- // If the value is an array then the key names need to be repeated
- if ( jQuery.isArray(a[j]) )
- jQuery.each( a[j], function(){
- add( j, this );
- });
- else
- add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
- // Return the resulting serialization
- return s.join("&").replace(/%20/g, "+");
- }//jquery.param end
上面是jQuery.param的代码,细心点可以留意到encodeURIComponent这方法,这是javascript内置的方法,对目标字符串执行utf-8 encode,因此,当页面使用gbk编码时候,服务端会使用gbk进行解码,但实际提交的数据是以utf-8编码的,所以造成接收到内容为乱码或者为问号。
解决方法:
encodeURIComponent会以utf-8编码,在gbk编码下,可不可以以gbk进行编码呢?
如果还在打encodeURIComponent主意的话,那不好意思,encodeURIComponent只会utf-8编码,并没有其他api进行其他编码;不过,别担心,看看下面:
encodeURIComponent,它是将中文、韩文等特殊字符转换成utf-8格式的url编码。
escape对0-255以外的unicode值进行编码时输出%u****格式,其它情况下escape,encodeURI,encodeURIComponent编码结果相同。
哈哈,看到希望吧?没错,就是用escape代替encodeURIComponent方法,不过必须注意:
escape不编码字符有69个:*,+,-,.,/,@,_,0-9,a-z,A-Z
encodeURIComponent不编码字符有71个:!, ',(,),*,-,.,_,~,0-9,a-z,A-Z
使用了escape之后必须对加号进行编码,否则,当内容含有加号时候会被服务端翻译为空格。
终于知道解决办法了,重写jquery代码:
- jQuery.param=function( a ) {
- var s = [ ];
- var encode=function(str){
- str=escape(str);
- str=str.replace(/+/g,"%u002B");
- return str;
- };
- function add( key, value ){
- s[ s.length ] = encode(key) + '=' + encode(value);
- };
- // If an array was passed in, assume that it is an array
- // of form elements
- if ( jQuery.isArray(a) || a.jquery )
- // Serialize the form elements
- jQuery.each( a, function(){
- add( this.name, this.value );
- });
- // Otherwise, assume that it's an object of key/value pairs
- else
- // Serialize the key/values
- for ( var j in a )
- // If the value is an array then the key names need to be repeated
- if ( jQuery.isArray(a[j]) )
- jQuery.each( a[j], function(){
- add( j, this );
- });
- else
- add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
- // Return the resulting serialization
- return s.join("&").replace(/%20/g, "+");
- }
上面那段代码并不需要在jquery的源文件重写,可以在你项目的javascript贴上,覆盖它原有的方法,不过必须在jquery加载之后。
经初步验证,上面那段代码在utf-8编码也可以工作正常,大概是编码成unicode的缘故吧。
这样,就不是需要使用什么二次编码,即影响前台,又影响后台。gbk编码下ajax post不再是问题了,此乃是终极解决方法。哈哈。
Sencha Touch Performance Tips and Tricks
How we worked with Sencha Touch 2 - some performance hints and other tips
Our team has been developing with Sencha Touch 2 since its pre-release days late 2011. We have spent a lot of time tweaking components and trying different techniques in order to speed up responsiveness - in an attempt to make it feel as native as possible. With the release of IOS6 on iPhone5 our latest version in development is pretty damn quick.
Why Sencha Touch 2?
The other great point to make is it's 'just JavaScript', you have full access to the source code, and with the use of the ExtJS 'Override' functionality you can really do just about anything to the core Sencha Touch 2 library, without modifying the library source code.
However, if you're not interested in the challenge and learning something new, maybe Sencha Touch 2 isn't for you..
What sort of applications should you use Sencha Touch 2 for?
- Content based apps
- News listings apps
- Daily deal apps
What sort of applications maybe not to use Sencha Touch 2 for?
- 3D games
- Any other sort of game
- Applications that require high processing power (and potentially a lot of high resolution imagery).
Final point before we get started
All docs:
http://docs.sencha.com/touch/2-0/.
Kitchecn sink demo:
http://docs.sencha.com/touch/2-0/touch-build/examples/production/kitchensink/index.html
This article is aimed at developers who have been using Sencha Touch 2 and want to find out some of the approaches we made to improve performance within our upcoming version 2 of our application.
Disclaimer:
A lot of what I mention can be found within the Sencha Touch 2 docs, or by looking directly into the codebase of Sencha Touch 2.
Improving performance with views/panels
Load all of your views/panels into the viewport at application startup:
- Your views/panels are in memory and ready to display when triggered by the users input.
- If you have only a few views (around 5-10) you can most likely get away with this approach without many performance issues.
- As soon as your application grows, you will start suffering massive performance issues, slow button tap responsiveness, slow list scrolling, memory warnings (in Xcode) etc..
- A much slower application bootup time.
Create and load your views/panels into the viewport on demand:
- You are only loading the views/panels that are required into memory.
- Faster button responsiveness.
- Less in memory which means a more responsive application.
- No more memory warnings from XCode.
- A little harder to implement.
- It will take an extra bit of time to create and render the view within the app when triggered by the user (simple tests show anywhere from 40ms to about 300ms).
/**
* app/views/viewport.js
*/
Ext.define('Demo.view.Viewport', {
extend: 'Ext.Container',
xtype: 'demo-viewport',
requires: [
// Home Loading
'Demo.view.home.Loading',
],
/**
* Configuration
* @property {object}
*/
config: {
layout: {
type: 'card',
animation: {
type: 'slide',
direction: 'left',
duration: 250
}
},
fullscreen: true,
items: [
// Home Loading
{xtype: 'home-loading'},
]
}
});
/**
* app/controller/Base.js
* We use a Base Controller to do the logic that is used throughout
* the application (eg: back button, memory handling of views etc..)
*/
Ext.define('Demo.controller.Base', {
extend: 'Ext.app.Controller',
/**
* Configuration
* @property {object}
*/
config: {
/**
* Refs
* @property {object}
*/
refs: {
/**
* @ignore
* Panels
*/
viewport: 'demo-viewport',
/**
* @ignore
* Buttons
*/
back: 'button[action=back]'
},
previousPanels: [],
/**
* Controls
* @property {object}
*/
control: {
/**
* Generic back to button (if you want one)
*/
back: {
tap: function(el, e){
var viewport = this.getViewport();
var activeItem = viewport.getActiveItem();
var view = activeItem.oldItem;
// Unset oldItem as its now been used
activeItem.oldItem = null;
// Set back animation
viewport.getLayout().setAnimation({type: 'slide', direction: 'right'});
// Go back to oldItem
viewport.setActiveItem(view);
if( e.event ) {
// Stop events from bubbling
e.stopEvent();
}
}
}
}
},
launch: function() {
var viewport = this.getViewport();
var baseController = this;
viewport.addBeforeListener(
'activeitemchange',
function( card, newItem, oldItem ){
// Fix for overlapping panels (explanation later)
// allow the panel to change
if (oldItem.aboutToBeVisible === true) {
newItem.aboutToBeVisible = false;
newItem.hide();
return false;
}
// flag that the new item is now in the process of being
// transitioned to
newItem.aboutToBeVisible = true;
// For the "Back" functionality
// Only set oldItem if its null,
// If its not null it means that there is an already set oldItem that
// should be used instead.
if( null == newItem.oldItem ){
newItem.oldItem = oldItem;
}
}
);
viewport.addAfterListener(
'activeitemchange',
function( card, newItem, oldItem ){
var index,
panels = baseController.getPreviousPanels(),
newId = newItem.getItemId();
// The below code ensures that only 5 view panels are kept in memory
// This is to speed up the application
for( index in panels ){
// If panel already exists in array, remove it
if (panels[index].getItemId() == newId) {
panels.splice(index, 1);
break;
}
}
// Add new item to top of array
panels.splice(0, 0, newItem);
// remove one panel from the back of the array
if( panels.length > 5 ) {
var panel = panels.pop();
panel.destroy();
}
// The new item is no longer transitioning, so flag it as such
newItem.aboutToBeVisible = false;
}
);
}
});
/**
* app/controller/Home.js
* Example of a controller in your application
*
*/
Ext.define('Demo.controller.Home', {
extend: 'Ext.app.Controller',
requires: [
'Demo.view.home.Index'
],
/**
* Configuration
* @property {object}
*/
config: {
/**
* Refs
* @property {object}
*/
refs: {
viewport: 'demo-viewport',
/**
* Defining all of your views to autoCreate: true will ensure
* Sencha will create them if the dont already exist in memory
*/
homeIndex: {
selector: 'home-index',
xtype: 'home-index',
autoCreate: true
}
},
/**
* Controls
* @property {object}
*/
control: {
/**
* Home index
*/
homeIndex: {
hide: function(){
},
show: function(){
}
}
}
}
});
Improving list scrolling and performance
Gradients and other CSS3 styles
High Resolution images in lists
- Low resolution images are smaller in file size:
- Requires less bandwidth to download each image.
- Smaller amount of data stored in local memory cache.
- Lower quality images animate faster (less processor intense).
- You can look into staggering the loading of images (so as to make less concurrent web requests). We do this, if you would like a code sample contact me.
Amount of items in list
Improving panel transitions and responsiveness
- Hiding/showing components
- Populating form data
- Populating dynamic data into panel.
- etc..
This approach allows your application to transition immediately to the next panel, giving a more native feel, and then doing the processing. See below:
/**
* app/controller/Portfolio.js
*
*/
Ext.define('Demo.controller.Portfolio', {
extend: 'Ext.app.Controller',
requires: [
'Demo.view.portfolio.Index'
],
/**
* Configuration
*/
config: {
/**
* Refs
*/
refs: {
viewport: 'demo-viewport',
portfolioIndex: {
selector: 'portfolio-index',
xtype: 'portfolio-index',
autoCreate: true
}
},
/**
* Controls
*/
control: {
/**
* Product index events
*/
index: {
show: function(){
var me = this;
Ext.create('Ext.util.DelayedTask', function () {
me.getIndex().fireEvent('showDelay');
}).delay(500);
// 500 should be set to more than your card layout transition time
},
showDelay: function(){
/**
* More processor intense processing can be done
* here, as panel will have been in view
*/
}
}
}
}
});
Screen overlay bug
I have only noticed this when using a card layout. Basically, this can happen if you click on multiple list items within a single list which both try to set different views as the active item within the card layout. Sencha attempts to show both views and can sometimes result in multiple panels being displayed over one another.
Another way to duplicate is (you may need 2 hands for this), if you have a view/panel with a button (potentially in the header) and a list item. If you repeatably tap both the list item and the button you will most likely be able to trigger this view/panel overlay bug.
Approaches we have used to resolve.
BaseController (preferred):Within the Base Controller we listen to the before and after events of the 'activeitemchange' for the viewports card layout. We manually track the when an item has being set as 'active item' within the card layout, by setting:
newItem.aboutToBeVisible = true;
Then once the after listener has been triggered we set:
newItem.aboutToBeVisible = false;
If 2 items are triggered in the before event as event, the secondary one hides itself and returns false.
/**
* app/controller/Base.js
*
*/
Ext.define('Demo.controller.Base', {
extend: 'Ext.app.Controller',
launch: function() {
var viewport = this.getViewport();
var baseController = this;
// Listen to the before event for setting activeItem in viewport.
viewport.addBeforeListener(
'activeitemchange',
function( card, newItem, oldItem ){
// Fix for overlapping panels
// If a panel is already in process of becoming visible,
// hide this new panel and return false to stop the transition.
if (oldItem.aboutToBeVisible === true) {
newItem.aboutToBeVisible = false;
newItem.hide();
return false;
}
// Set that the new item is now in the process of being transitioned to
newItem.aboutToBeVisible = true;
// If not null set oldItem so we can use the back button
if( null == newItem.oldItem ){
newItem.oldItem = oldItem;
}
}
);
// Listen to the before event for setting activeItem in viewport.
viewport.addAfterListener(
'activeitemchange',
function( card, newItem, oldItem ){
var index,
panels = baseController.getPreviousPanels(),
newId = newItem.getItemId();
// The below code ensures that only 5 view panels are kept in memory
// This is to speed up the application
for( index in panels ){
// If panel already exists in array, remove it
if (panels[index].getItemId() == newId) {
panels.splice(index, 1);
break;
}
}
// Add new item to top of array
panels.splice(0, 0, newItem);
// remove one panel from the back of the array
if( panels.length > 5 ) {
var panel = panels.pop();
panel.destroy();
}
// The new item is no longer transitioning, so flag it as such
newItem.aboutToBeVisible = false;
}
);
}
});
Buttons:
/**
* app/override/Button.js
*/
Ext.define('Demo.override.Button', {
override: 'Ext.Button',
lastTapped: 0,
/**
* Update button icon to support masking
* @return {String} icon
*/
updateIcon: function(icon) {
var me = this,
element = me.iconElement;
if (icon) {
me.showIconElement();
if( this.getIconMask() ){
element.setStyle('-webkit-mask-image', icon ? 'url(' + icon + ')' : '');
} else {
element.setStyle('background-image', icon ? 'url(' + icon + ')' : '');
}
me.refreshIconAlign();
me.refreshIconMask();
}
else {
me.hideIconElement();
me.setIconAlign(false);
}
},
/**
* On slower devices Sencha registers multiple button taps
* which ends up causing strange behaviour. Ensure only a single
* button tap every 2seconds per button
*/
onTap: function(e) {
var now = Date.now();
if (this.getDisabled()) {
return false;
}
if ( (now - this.lastTapped) > 2000 ) {
this.lastTapped = now;
this.fireAction('tap', [this, e], 'doTap');
}
}
});
Native components
Essentially what this means is our application is coded to work entirely within the browser first. All functionality must work in a browser. We then add the specifics eg:
- Passbook functionality (on IOS6) - only visible on IOS6 devices.
- Local notifications (eg: setting up calendar reminders) - Only available on the iPhone - to any other user (web browser) this functionality is not available/hidden.
- Email composer - only available if within Cordova application.
Compile your JavaScript
Always compile your javascript into app-all.js.
- index-dev.html
<html> <head> <link href="css/application.css" rel="stylesheet" type="text/css"></link> </head> <body> <script> // Define environment var settings = { environment: 'development' }; </script> <script src="app/ConfigurationDev.js"></script> <script src="lib/sencha/sencha-touch-debug.js"></script> <script src="app.js"></script> </body> </html> - index.html
This is our production environment.
Includes the cordova plugins and the compiled Sencha Touch 2 files:
<head> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" /> <meta name="apple-mobile-web-app-capable" content="yes" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <link href="css/application.css" rel="stylesheet" type="text/css" /> </head> <body> <script> console.log = function(){}; </script> <!-- Load up cordova plugins --> <script type="text/javascript" src="lib/cordova/cordova-1.8.1.js"></script> <script type="text/javascript" src="lib/cordova/NotificationEx.js"></script> <script type="text/javascript" src="lib/cordova/LocalNotification.js"></script> <script type="text/javascript" src="lib/cordova/PushNotification.js"></script> <script type="text/javascript" src="lib/cordova/PixAuth.js"></script> <script type="text/javascript" src="lib/cordova/ChildBrowser.js"></script> <script type="text/javascript" src="lib/cordova/SMSComposer.js"></script> <script type="text/javascript" src="lib/cordova/EmailComposer.js"></script> <script type="text/javascript" src="app-all.js"></script> </body> </html>
Configuration setup
- Production (default)
- Staging
- Emulator (Used for automated user testing)
- Development (included only within the index-dev.html file)
/**
* app/Configuration.js
*/
var settings = settings || {
environment: 'production'
};
/**
* Production environment
*/
settings.production = {
'version': '2.0',
'api.user': '',
'api.key': '',
'api.timeout': 30000,
'logger.writer.db': true,
'logger.writer.alert': false,
'logger.writer.console': false,
'logger.writer.remote': true,
// Cache
'cache.user.login': 3600,
'cache.configuration.list': 86400,
// Our system has 2 performance profiles
// High profile - for newer phones (iPhone 4S & 5)
'performance.high.base.transition.time': 250,
'performance.high.scrolltotop.time': 500,
'performance.high.list.acceleration': 15,
'performance.high.list.friction': 0.3,
// Low profile - for older phones (iPhone 3S, 4)
'performance.low.base.transition.time': 400,
'performance.low.scrolltotop.time': 750,
'performance.low.list.acceleration': 10,
'performance.low.list.friction': 0.4
};
/**
* Staging overrides
*/
settings.staging = {
'api.user': '',
'api.key': ''
};
/**
* Development environment
* @ignore
*
* See app/ConfigurationDev.js
*/
/**
* Override configuration with merged config.
* This is so there is no possible way settings
* from other environments can be accessed unless
* through the configuration object
*/
for( var i in settings.production ) {
settings[i] = settings.production[i];
}
// This defines which environment will be deployed
for( var i in settings[settings.environment] ) {
settings[i] = settings[settings.environment][i];
}
settings.production = undefined;
settings.staging = undefined;
settings.development = undefined;
settings.emulator = undefined;
/**
* All configuration within application goes through this object
*/
Ext.define('Demo.Configuration', {
/**
* Performance profile high
*/
PERFORMANCE_HIGH: 'high',
/**
* Performance profile low
*/
PERFORMANCE_LOW: 'low',
/**
* Configuration
* @property {object}
*/
config: {
settings: settings,
performance: null
},
/**
* Singleton
*/
singleton: true,
/**
* Constructor
* @contructor
*/
constructor: function(config) {
if( undefined == config ) {
config = {};
}
// Default performance to high
config.performance = this.PERFORMANCE_HIGH;
// If devicePixelRatio is 1, it implies low res display (on iphone)
// Drop performance to low for this device
if( 1 == window.devicePixelRatio ) {
config.performance = this.PERFORMANCE_LOW;
}
this.initConfig(config);
},
/**
* Get property
*
* @param {String} name
* @return {String}
*/
getProperty: function( name )
{
return this.getSettings()[name];
},
/**
* Set property
* Not is use yet
*
* @param {String} name
* @param {String} value
*/
setProperty: function( name, value )
{
this.getSettings()[name] = value;
},
/**
* Get properties
*/
getProperties: function()
{
return this.getSettings();
},
/**
* Get environment
*/
getEnvironment: function()
{
return this.getSettings().environment;
},
/**
* Is environment development
*/
isEnvironmentDevelopment: function()
{
return ('development' == this.getSettings().environment);
},
/**
* Is environment staging
*/
isEnvironmentStaging: function()
{
return ('staging' == this.getSettings().environment);
},
/**
* Is environment production
*/
isEnvironmentProduction: function()
{
return ('production' == this.getSettings().environment);
},
/**
* Get a config value based off profile in use
*/
setPerformanceHigh: function()
{
// Set performance to high
this.setPerformance(this.PERFORMANCE_HIGH);
},
/**
* Get a config value based off profile in use
*/
getPerformanceProperty: function(name)
{
return this.getProperty('performance.' + this.getPerformance() + '.' + name);
}
});
Design Requests:
My advice, start simple, add new features with care. Benchmark and test each change on actual devices to be certain there are no huge performance issues.
Develop in Chrome for fast development - we dramatically increased our development speed by being able to develop directly within chrome. However, constantly test your features in the simulator and the device - otherwise you will find yourself with problems later on in the project.
Working code sample
Demo application
Create a virtual host
For development go to
http://virtualhost/index-dev.html
For production go to
http://virtualhost/index.html
I use the above one with Cordova (previously PhoneGap). If there is any interest I will include the Cordova configuration within the code sample.
Hope you learned something from my blog post, any questions let me know..
Dion Beetson
Founder of www.ackwired.com
Linked in: www.linkedin.com/in/dionbeetson
Twitter: www.twitter.com/dionbeetson
Website: www.dionbeetson.com
2013年十五个最新的科技及IT技术RSS订阅源
Google 将在7月1日关闭 Reader 阅读器,让笔者非常惋惜。Google Reader对中国用户的意义和其他国家不一样。就目前来看还没有能够替代Google Reader的产品,它的关闭直接关上了我们了解外面世界的一扇大门。因为本来我们可以通过某种方式不需要穿越防火墙而快速地访问Reader,甚至Twitter信息,而且它还采用了HTTPS协议,避免遭遇非常不愉快的阅读体验。当然,对于只是关注科技和IT技术的朋友可以挑选任何在线的和离线的RSS阅读器,来订阅国内的资讯,笔者在这里收集精选了一些科技和IT技术Rss 订阅源。
这些RSS订阅源基本遵循如下原则:
- 保持每天更新但不是太频繁,对新内容保持跟踪的同时不带来太大负担
- 大多与科技或IT技术有关,适合科技和IT技术从业者
- 大部分是原创内容,避免太多重复内容
- RSS输出文章全文内容,方便离线阅读
1、雷锋网:雷锋网是专注于移动互联网创新和创业的科技博客,客观敏锐地记录移动互联网的每一天。雷锋网由一群移动互联网的信徒建立,他们中有投资人,有观察者,有产品经理,有资深玩家,还有创业者。
http://www.leiphone.com/feed
2、互联网那些事:互联网那点事精心打造国内互联网产品信息门户站点。为产品策划和产品运营人士提供专业的产品资讯文档,以及产品设计、策划、运营、交互设计、用户体验、电子商务信息、互联网创业信息、移动互联网等专业信息服务。
http://feed.feedsky.com/alibuybuy
3、月光博客:月光博客,是一个专注于电脑技术、网站架设互联网、搜索引擎行业、Google Earth、Web 2.0等的原创IT科技博客。
http://feed.williamlong.info/
4、爱范儿:爱范儿是发现创新价值的科技媒体。 全景关注移动互联网,集中报道创业团队、最潮的智能手持及最酷的互联网应用,致力于“独立,前瞻,深入”的分析评论.
http://www.ifanr.com/feed
5、cnBeta:cnBeta.com提供最新最快的IT业界资讯,报导立场公正中立,.创造最适合目标人群阅读的新闻、评论、观点和专访。
http://www.cnbeta.com/backend.php
全文版RSS:http://pipes.yahoo.com/pipes/pipe.run?_id=5OVll5Fs3hGCc1KftJCjyQ&_render=rss
6、ITeye:ITeye资讯频道最新资讯,报道移动开发,WEB前端,企业构架,Java新闻,Ruby新闻,Python、Rails、PHP等编程开发技术资讯
http://www.iteye.com/rss/news
7、IT瘾资讯推荐:IT瘾推荐资讯,推荐关于互联网科技,手持设备,编程软件开发,信息技术,Google,Android等资讯
http://itindex.net/feed.jsp
8、36氪:关注互联网新媒体以及创业的科技博客,是中国领先的科技新媒体,报道最新的互联网科技新闻以及最有潜力的互联网创业企业。36氪的目标是,通过对互联网行业及最新创业企业的关注,为中文互联网读者提供一个最佳的了解互联网行业当下与未来的科技媒体。
http://www.36kr.com/feed/
9、Engadget 中国版:Engadget的中文站点,报道计算机硬件,数码/消费电子产品,科技新闻。
http://cn.engadget.com/rss.xml
10、PingWest:PingWest是一家提供关于硅谷与中国最前沿科技创业资讯、趋势与洞见的在线媒体,致力于成为沟通中国与美国这两个全球最大的互联网/移动市场的互联网社区。
http://feed.feedsky.com/pingwest
11、InfoQ:InfoQ是一个实践驱动的社区资讯站点,致力于促进软件开发领域知识与创新的传播。
http://www.infoq.com/cn/rss/rss.action?token=yV5lHoM3uVZTqXcuTdyeDFK4uzcE6XNQ
InfoQ全文版:http://pipes.yahoo.com/pipes/pipe.run?_id=10560380f804c7341f042a2b8a03e117&_render=rss
12、TechWeb:科技媒体,新媒体、新技术、新商业互动交流平台。
http://www.techweb.com.cn/rss/hotnews.xml
13、伯乐在线:伯乐在线-博客专注于分享职业相关的博客文章、业界资讯和职业相关的优秀工具和资源。
http://blog.jobbole.com/feed/
14、极客公园:发现产品价值,带来互联网热门趋势、热点产品的深度分析,发掘产品和趋势的价值
http://feeds.geekpark.net/
15、奇客Solidot:奇客的资讯,重要的东西
http://www.solidot.org/index.rss
本文精选15个RSS 订阅源,试图通过这些订阅源让你保持对科技和IT技术的跟踪,适合从事科技行业或IT技术的人订阅,让你不错过重大的科技资讯、创新产品和新兴技术。
weblogic9.x与 xfire1.2.6冲突解决心得 - ljhmustang的日志 - 网易博客
- Caused by: java.lang.UnsupportedOperationException
- at weblogic.xml.stax.XMLStreamReaderBase.getTextCharacters(XMLStreamReaderBase.java:487)
解决方法1:
添加weblogic.xml文件到WEN-INF
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd">
<context-root>/sxwh</context-root>
<container-descriptor>
<prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>
</weblogic-web-app>
解决方法2:
My solution to the problem in the original post: In the META-INF directory of the JAR file add a directory namedservices. In this directory place a file named javax.xml.stream.XMLInputFactory with the following contents:com.sun.xml.internal.stream.XMLInputFactoryImplFor more details seehttp://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html#newFactory%28%29
JVM调优总结 -Xms -Xmx -Xmn -Xss - 天下无贼 - 51CTO技术博客
- 堆大小设置
JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。
典型设置:- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-Xmx3550m:设置JVM最大可用内存为3550M。
-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn2g:设置年轻代大小为2G。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m.整个堆大小=年轻代大小 + 年老代大小.所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。 - java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m。
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
- 回收器选择
JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默认情况下,JDK5.0以前都是使用串行收集器,如果想使用其他收集器需要在启动时加入相应参数。JDK5.0以后,JVM会根据当前系统配置进行判断。- 吞吐量优先的并行收集器
如上文所述,并行收集器主要以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
典型配置:- java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。
- java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20
- 响应时间优先的并发收集器
如上文所述,并发收集器主要是保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。
典型配置:- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。
-XX:+UseParNewGC:设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。 - java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5 -XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC
- 吞吐量优先的并行收集器
- 辅助信息
JVM提供了大量命令行参数,打印信息,供调试使用。主要有以下一些:- -XX:+PrintGC
输出形式:[GC 118250K->113543K(130112K), 0.0094143 secs][Full GC 121376K->10414K(130112K), 0.0650971 secs] - -XX:+PrintGCDetails
输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs][GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs] - -XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可与上面两个混合使用
输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs] - -XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中断的执行时间。可与上面混合使用
输出形式:Application time: 0.5291524 seconds - -XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间。可与上面混合使用
输出形式:Total time for which application threads were stopped: 0.0468229 seconds - -XX:PrintHeapAtGC:打印GC前后的详细堆栈信息
输出形式:
34.702: [GC {Heap before gc invocations=7:
def new generation total 55296K, used 52568K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 99% used [0x1ebd0000, 0x21bce430, 0x21bd0000)
from space 6144K, 55% used [0x221d0000, 0x22527e10, 0x227d0000)
to space 6144K, 0% used [0x21bd0000, 0x21bd0000, 0x221d0000)
tenured generation total 69632K, used 2696K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 3% used [0x227d0000, 0x22a720f8, 0x22a72200, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
34.735: [DefNew: 52568K->3433K(55296K), 0.0072126 secs] 55264K->6615K(124928K)Heap after gc invocations=8:
def new generation total 55296K, used 3433K [0x1ebd0000, 0x227d0000, 0x227d0000)
eden space 49152K, 0% used [0x1ebd0000, 0x1ebd0000, 0x21bd0000)
from space 6144K, 55% used [0x21bd0000, 0x21f2a5e8, 0x221d0000)
to space 6144K, 0% used [0x221d0000, 0x221d0000, 0x227d0000)
tenured generation total 69632K, used 3182K [0x227d0000, 0x26bd0000, 0x26bd0000)
the space 69632K, 4% used [0x227d0000, 0x22aeb958, 0x22aeba00, 0x26bd0000)
compacting perm gen total 8192K, used 2898K [0x26bd0000, 0x273d0000, 0x2abd0000)
the space 8192K, 35% used [0x26bd0000, 0x26ea4ba8, 0x26ea4c00, 0x273d0000)
ro space 8192K, 66% used [0x2abd0000, 0x2b12bcc0, 0x2b12be00, 0x2b3d0000)
rw space 12288K, 46% used [0x2b3d0000, 0x2b972060, 0x2b972200, 0x2bfd0000)
}
, 0.0757599 secs] - -Xloggc:filename:与上面几个配合使用,把相关日志信息记录到文件以便分析。
- -XX:+PrintGC
- 常见配置汇总
- 堆设置
- -Xms:初始堆大小
- -Xmx:最大堆大小
- -XX:NewSize=n:设置年轻代大小
- -XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
- -XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
- -XX:MaxPermSize=n:设置持久代大小
- 收集器设置
- -XX:+UseSerialGC:设置串行收集器
- -XX:+UseParallelGC:设置并行收集器
- -XX:+UseParalledlOldGC:设置并行年老代收集器
- -XX:+UseConcMarkSweepGC:设置并发收集器
- 垃圾回收统计信息
- -XX:+PrintGC
- -XX:+PrintGCDetails
- -XX:+PrintGCTimeStamps
- -Xloggc:filename
- 并行收集器设置
- -XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
- -XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
- -XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
- 并发收集器设置
- -XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。
- -XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
- 堆设置
四、调优总结
- 年轻代大小选择
- 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。
- 吞吐量优先的应用:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。
- 年老代大小选择
- 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:
- 并发垃圾收集信息
- 持久代并发收集次数
- 传统GC信息
- 花在年轻代和年老代回收上的时间比例
- 吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。
- 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:
- 较小堆引起的碎片问题
因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:- -XX:+UseCMSCompactAtFullCollection:使用并发收集器时,开启对年老代的压缩。
- -XX:CMSFullGCsBeforeCompaction=0:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩
Android压缩图片到100K以下并保持不失真的高效方法 - feicien的博客 - eoe移动开发者社区
1.获取原始图片的长和宽
以上代码是对图片进行解码,inJustDecodeBounds设置为true,可以不把图片读到内存中,但依然可以计算出图片的大小,这正好可以满足我们第一步的需要。
2.计算压缩比例
一般手机的分辨率为 480*800 ,所以我们压缩后图片期望的宽带定为480,高度设为800,这2个值只是期望的宽度与高度,实际上压缩后的实际宽度也高度会比期望的要大。如果图片的原始高度或者宽带大约我们期望的宽带和高度,我们需要计算出缩放比例的数值。否则就不缩放。heightRatio是图片原始高度与压缩后高度的倍数,widthRatio是图片原始宽度与压缩后宽度的倍数。inSampleSize为heightRatio与widthRatio中最小的那个,inSampleSize就是缩放值。 inSampleSize为1表示宽度和高度不缩放,为2表示压缩后的宽度与高度为原来的1/2
3.缩放并压缩图片
前3行的代码其实已经得到了一个缩放的bitmap对象,如果你在应用中显示图片,就可以使用这个bitmap对象了。由于考虑到网络流量的问题。我们好需要牺牲图片的质量来换取一部分空间,这里调用bm.compress()方法进行压缩,这个方法的第二个参数,如果是100,表示不压缩,我这里设置的是60,你也可以更加你的需要进行设置,在实验的过程中我设置为30,图片都不会失真。
Android 调用系统拍照 笔记 - 会说话的哑巴的个人页面 - 开源中国社区
用以上代码碰到的问题:
- 在MIUI下无法取到照片数据,跟踪发现data.getExtras()为空,之后使用BitmapFactory.decodeFile()方法解决;
- 手机上测试没有保存图片,跟踪发现data为null,继续Google,找到以下代码
| 1 | Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); |
| 2 | Uri uri = Uri.fromFile(new File(imagePath)); |
| 3 | intent.putExtra(MediaStore.EXTRA_OUTPUT,uri); |
| 4 | startActivityForResult(intent,RESULT_CAPTURE_IMAGE); |
将按钮onClick方法中采用以上代码,调用系统拍照并确定之后,无法返回程序Activity。继续Google,终于找到解决办法,代码如下(在 if(resultCode == RESULT_OK)里面)
| 01 | Bitmap bitmap = null; |
| 02 | File file = new File(imagePath); |
| 03 | bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); |
| 04 | if(bitmap == null) { |
| 05 | Toast.makeText(this,R.string.image_save_error,Toast.LENGTH_LONG).show(); |
| 06 | } |
| 07 | try { |
| 08 | BufferOutputStream bos = new BufferOutputStream(new FileOutputStream(file)); |
| 09 | bitmap.compress(Bitmap.CompressFormat.JPEG,80,bos); |
| 10 | bos.flush(); |
| 11 | bos.close(); |
| 12 | }catch(FileNotFoundException e) { |
| 13 | e.printStackTrace(); |
| 14 | }catch(IOException e) { |
| 15 | e.printStackTrace(); |
| 16 | } |
| 17 | super.onActivityResult(requestCode,resultCode,data); |
Git 常用命令详解(二) - IT-Homer - 博客频道 - CSDN.NET
1) 远程仓库相关命令
检出仓库: $ git clone git://github.com/jquery/jquery.git
查看远程仓库:$ git remote -v
添加远程仓库:$ git remote add [name] [url]
删除远程仓库:$ git remote rm [name]
修改远程仓库:$ git remote set-url --push [name] [newUrl]
拉取远程仓库:$ git pull [remoteName] [localBranchName]
推送远程仓库:$ git push [remoteName] [localBranchName]
*如果想把本地的某个分支test提交到远程仓库,并作为远程仓库的master分支,或者作为另外一个名叫test的分支,如下:
$git push origin test:master // 提交本地test分支作为远程的master分支
$git push origin test:test // 提交本地test分支作为远程的test分支
