`
lxx_amy
  • 浏览: 15709 次
  • 性别: Icon_minigender_2
  • 来自: 黄冈
最近访客 更多访客>>
社区版块
存档分类
最新评论
收藏列表
标题 标签 来源
j Query使用技巧总结 jquery jquery使用技巧总结
jquery使用技巧总结
一、简介

1.1、概述
随着WEB2.0及ajax思想在互联网上的快速发展传播,陆续出现了一些优秀的Js框架,其中比较著名的有Prototype、YUI、jQuery、mootools、Bindows以及国内的JSVM框架等,通过将这些JS框架应用到我们的项目中能够使程序员从设计和书写繁杂的JS应用中解脱出来,将关注点转向功能需求而非实现细节上,从而提高项目的开发速度。
jQuery是继prototype之后的又一个优秀的Javascript框架。它是由 John Resig 于 2006 年初创建的,它有助于简化 JavaScript™ 以及Ajax 编程。有人使用这样的一比喻来比较prototype和jQuery:prototype就像Java,而jQuery就像ruby. 它是一个简洁快速灵活的JavaScript框架,它能让你在你的网页上简单的操作文档、处理事件、实现特效并为Web页面添加Ajax交互。

它具有如下一些特点:
1、代码简练、语义易懂、学习快速、文档丰富。
2、jQuery是一个轻量级的脚本,其代码非常小巧,最新版的JavaScript包只有20K左右。
3、jQuery支持CSS1-CSS3,以及基本的xPath。
4、jQuery是跨浏览器的,它支持的浏览器包括IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+。
5、可以很容易的为jQuery扩展其他功能。
6、能将JS代码和HTML代码完全分离,便于代码和维护和修改。
7、插件丰富,除了jQuery本身带有的一些特效外,可以通过插件实现更多功能,如表单验证、tab导航、拖放效果、表格排序、DataGrid,树形菜单、图像特效以及ajax上传等。

jQuery的设计会改变你写JavaScript代码的方式,降低你学习使用JS操作网页的复杂度,提高网页JS开发效率,无论对于js初学者还是资深专家,jQuery都将是您的首选。
jQuery适合于设计师、开发者以及那些还好者,同样适合用于商业开发,可以说jQuery适合任何JavaScript应用的地方,可用于不同的Web应用程序中。
官方站点:http://jquery.com/  中文站点:http://jquery.org.cn/

1.2、目的
通过学习本文档,能够对jQuery有一个简单的认识了解,清楚JQuery与其他JS框架的不同,掌握jQuery的常用语法、使用技巧及注意事项。

二、使用方法
在需要使用JQuery的页面中引入JQuery的js文件即可。
例如:<script type="text/javascript" src="js/jquery.js"></script>
引入之后便可在页面的任意地方使用jQuery提供的语法。

三、学习教程及参考资料
请参照《jQuery中文API手册》和http://jquery.org.cn/visual/cn/index.xml
推荐两篇不错的jquery教程:《jQuery的起点教程》和《使用 jQuery 简化 Ajax 开发》
(说明:以上文档都放在了【附件】中)

四、语法总结和注意事项

1、关于页面元素的引用
通过jquery的$()引用元素包括通过id、class、元素名以及元素的层级关系及dom或者xpath条件等方法,且返回的对象为jquery对象(集合对象),不能直接调用dom定义的方法。

2、jQuery对象与dom对象的转换
只有jquery对象才能使用jquery定义的方法。注意dom对象和jquery对象是有区别的,调用方法时要注意操作的是dom对象还是jquery对象。
普通的dom对象一般可以通过$()转换成jquery对象。
如:$(document.getElementById("msg"))则为jquery对象,可以使用jquery的方法。
由于jquery对象本身是一个集合。所以如果jquery对象要转换为dom对象则必须取出其中的某一项,一般可通过索引取出。
如:$("#msg")[0],$("div").eq(1)[0],$("div").get()[1],$("td")[5]这些都是dom对象,可以使用dom中的方法,但不能再使用Jquery的方法。
以下几种写法都是正确的:
$("#msg").html();
$("#msg")[0].innerHTML;
$("#msg").eq(0)[0].innerHTML;
$("#msg").get(0).innerHTML;

3、如何获取jQuery集合的某一项
对于获取的元素集合,获取其中的某一项(通过索引指定)可以使用eq或get(n)方法或者索引号获取,要注意,eq返回的是jquery对象,而get (n)和索引返回的是dom元素对象。对于jquery对象只能使用jquery的方法,而dom对象只能使用dom的方法,如要获取第三个< div>元素的内容。有如下两种方法:
$("div").eq(2).html();              //调用jquery对象的方法
$("div").get(2).innerHTML;       //调用dom的方法属性

4、同一函数实现set和get
Jquery中的很多方法都是如此,主要包括如下几个:
$("#msg").html();              //返回id为msg的元素节点的html内容。
$("#msg").html("<b>new content</b>");      
//将“<b>new content</b>” 作为html串写入id为msg的元素节点内容中,页面显示粗体的new content

$("#msg").text();              //返回id为msg的元素节点的文本内容。
$("#msg").text("<b>new content</b>");      
//将“<b>new content</b>” 作为普通文本串写入id为msg的元素节点内容中,页面显示粗体的<b>new content</b>

$("#msg").height();              //返回id为msg的元素的高度
$("#msg").height("300");       //将id为msg的元素的高度设为300
$("#msg").width();              //返回id为msg的元素的宽度
$("#msg").width("300");       //将id为msg的元素的宽度设为300

$("input").val(");       //返回表单输入框的value值
$("input").val("test");       //将表单输入框的value值设为test

$("#msg").click();       //触发id为msg的元素的单击事件
$("#msg").click(fn);       //为id为msg的元素单击事件添加函数
同样blur,focus,select,submit事件都可以有着两种调用方法

5、集合处理功能
对于jquery返回的集合内容无需我们自己循环遍历并对每个对象分别做处理,jquery已经为我们提供的很方便的方法进行集合的处理。
包括两种形式:
$("p").each(function(i){this.style.color=['#f00','#0f0','#00f']})      
//为索引分别为0,1,2的p元素分别设定不同的字体颜色。

$("tr").each(function(i){this.style.backgroundColor=['#ccc','#fff'][i%2]})      
//实现表格的隔行换色效果

$("p").click(function(){.html())})              
//为每个p元素增加了click事件,单击某个p元素则弹出其内容

6、扩展我们需要的功能
$.extend({
       min: function(a, b){return a < b?a:b; },
       max: function(a, b){return a > b?a:b; }
});       //为jquery扩展了min,max两个方法
使用扩展的方法(通过“$.方法名”调用):
+",min="+$.min(10,20));

7、支持方法的连写
所谓连写,即可以对一个jquery对象连续调用各种不同的方法。
例如:
$("p").click(function(){.html())})
.mouseover(function(){})
.each(function(i){this.style.color=['#f00','#0f0','#00f']});

8、操作元素的样式
主要包括以下几种方式:
$("#msg").css("background");              //返回元素的背景颜色
$("#msg").css("background","#ccc")       //设定元素背景为灰色
$("#msg").height(300); $("#msg").width("200");       //设定宽高
$("#msg").css({ color: "red", background: "blue" });//以名值对的形式设定样式
$("#msg").addClass("select");       //为元素增加名称为select的class
$("#msg").removeClass("select");       //删除元素名称为select的class
$("#msg").toggleClass("select");       //如果存在(不存在)就删除(添加)名称为select的class

9、完善的事件处理功能
Jquery已经为我们提供了各种事件处理方法,我们无需在html元素上直接写事件,而可以直接为通过jquery获取的对象添加事件。
如:
$("#msg").click(function(){})       //为元素添加了单击事件
$("p").click(function(i){this.style.color=['#f00','#0f0','#00f']})
//为三个不同的p元素单击事件分别设定不同的处理
jQuery中几个自定义的事件:
(1)hover(fn1,fn2):一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法。当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时,会触发指定的第二个函数。
//当鼠标放在表格的某行上时将class置为over,离开时置为out。
$("tr").hover(function(){
$(this).addClass("over");
},
       function(){
       $(this).addClass("out");
});
(2)ready(fn):当DOM载入就绪可以查询及操纵时绑定一个要执行的函数。
$(document).ready(function(){})
//页面加载完毕提示“Load Success”,相当于onload事件。与$(fn)等价
(3)toggle(evenFn,oddFn): 每次点击时切换要调用的函数。如果点击了一个匹配的元素,则触发指定的第一个函数,当再次点击同一元素时,则触发指定的第二个函数。随后的每次点击都重复对这两个函数的轮番调用。
       //每次点击时轮换添加和删除名为selected的class。
       $("p").toggle(function(){
              $(this).addClass("selected");   
       },function(){
              $(this).removeClass("selected");
       });
(4)trigger(eventtype): 在每一个匹配的元素上触发某类事件。
例如:
       $("p").trigger("click");              //触发所有p元素的click事件
(5)bind(eventtype,fn),unbind(eventtype): 事件的绑定与反绑定
从每一个匹配的元素中(添加)删除绑定的事件。
例如:
$("p").bind("click", function(){.text());});       //为每个p元素添加单击事件
$("p").unbind();       //删除所有p元素上的所有事件
$("p").unbind("click")       //删除所有p元素上的单击事件

10、几个实用特效功能
其中toggle()和slidetoggle()方法提供了状态切换功能。
如toggle()方法包括了hide()和show()方法。
slideToggle()方法包括了slideDown()和slideUp方法。

11、几个有用的jQuery方法
$.browser.浏览器类型:检测浏览器类型。有效参数:safari, opera, msie, mozilla。如检测是否ie:$.browser.isie,是ie浏览器则返回true。
$.each(obj, fn):通用的迭代函数。可用于近似地迭代对象和数组(代替循环)。
如
$.each( [0,1,2], function(i, n){ ; });
等价于:
var tempArr=[0,1,2];
for(var i=0;i<tempArr.length;i++){
       ;
}
也可以处理json数据,如
$.each( { name: "John", lang: "JS" }, function(i, n){ ; });
结果为:
Name:name, Value:John
Name:lang, Value:JS
$.extend(target,prop1,propN):用一个或多个其他对象来扩展一个对象,返回这个被扩展的对象。这是jquery实现的继承方式。
如:
$.extend(settings, options);      
//合并settings和options,并将合并结果返回settings中,相当于options继承setting并将继承结果保存在setting中。
var settings = $.extend({}, defaults, options);
//合并defaults和options,并将合并结果返回到setting中而不覆盖default内容。
可以有多个参数(合并多项并返回)
$.map(array, fn):数组映射。把一个数组中的项目(处理转换后)保存到到另一个新数组中,并返回生成的新数组。
如:
var tempArr=$.map( [0,1,2], function(i){ return i + 4; });
tempArr内容为:[4,5,6]
var tempArr=$.map( [0,1,2], function(i){ return i > 0 ? i + 1 : null; });
tempArr内容为:[2,3]
$.merge(arr1,arr2):合并两个数组并删除其中重复的项目。
如:$.merge( [0,1,2], [2,3,4] )       //返回[0,1,2,3,4]
$.trim(str):删除字符串两端的空白字符。
如:$.trim("  hello, how are you?   ");        //返回"hello,how are you? "

12、解决自定义方法或其他类库与jQuery的冲突
很多时候我们自己定义了$(id)方法来获取一个元素,或者其他的一些js类库如prototype也都定义了$方法,如果同时把这些内容放在一起就会引起变量方法定义冲突,Jquery对此专门提供了方法用于解决此问题。
使用jquery中的jQuery.noConflict();方法即可把变量$的控制权让渡给第一个实现它的那个库或之前自定义的$方法。之后应用 Jquery的时候只要将所有的$换成jQuery即可,如原来引用对象方法$("#msg")改为jQuery("#msg")。
如:
jQuery.noConflict();
// 开始使用jQuery
jQuery("div   p").hide();
// 使用其他库的 $()
$("content").style.display = 'none';
jQuery的使用技巧 jquery 常见26个jquery使用技巧详
本文列出jquery一些应用小技巧,比如有禁止右键点击、隐藏搜索文本框文字、在新窗口中打开链接、检测浏览器、预加载图片、页面样式切换、所有列等高、动态控制页面字体大小、获得鼠标指针的X值Y值、验证元素是否为空、替换元素、延迟加载、验证元素是否存在于Jquery集合中、使DIV可点击、克隆对象、使元素居中、计算元素个数、使用Google主机上的Jquery类库、禁用Jquery效果、解决Jquery类库与其他 Javascript类库冲突问题。

请看下文jquery技巧:

1. 禁止右键点击
1.       $(document).ready(function(){  
2.           $(document).bind("contextmenu",function(e){  
3.               return false;  
4.           });  
5.       }); 
2. 隐藏搜索文本框文字
1.       $(document).ready(function() {  
2.       $("input.text1").val("Enter your search text here");  
3.          textFill($('input.text1'));  
4.       });  
5.        
6.           function textFill(input){ //input focus text function  
7.           var originalvalue = input.val();  
8.           input.focus( function(){  
9.               if( $.trim(input.val()) == originalvalue ){ input.val(''); }  
10.       });  
11.       input.blur( function(){  
12.           if( $.trim(input.val()) == '' ){ input.val(originalvalue); }  
13.       });  
14.   } 
3. 在新窗口中打开链接
1.       $(document).ready(function() {  
2.          //Example 1: Every link will open in a new window  
3.          $('a[href^="http://"]').attr("target", "_blank");  
4.        
5.          //Example 2: Links with the rel="external" attribute will only open in a new window  
6.          $('a[@rel$='external']').click(function(){  
7.             this.target = "_blank";  
8.          });  
9.       });  
10.   // how to use  
11.   open link 

4. 检测浏览器注: 在版本jQuery 1.4中,$.support 替换掉了$.browser 变量。

1.       $(document).ready(function() {  
2.       // Target Firefox 2 and above  
3.       if ($.browser.mozilla && $.browser.version >= "1.8" ){  
4.           // do something  
5.       }  
6.        
7.       // Target Safari  
8.       if( $.browser.safari ){  
9.           // do something  
10.   }  
11.    
12.   // Target Chrome  
13.   if( $.browser.chrome){  
14.       // do something  
15.   }  
16.    
17.   // Target Camino  
18.   if( $.browser.camino){  
19.       // do something  
20.   }  
21.    
22.   // Target Opera  
23.   if( $.browser.opera){  
24.       // do something  
25.   }  
26.    
27.   // Target IE6 and below  
28.   if ($.browser.msie && $.browser.version <= 6 ){  
29.       // do something  
30.   }  
31.    
32.   // Target anything above IE6  
33.   if ($.browser.msie && $.browser.version > 6){  
34.       // do something  
35.   }  
36.   }); 
5. 预加载图片
1.       $(document).ready(function() {  
2.          jQuery.preloadImages = function()  
3.         {  
4.            for(var i = 0; i").attr("src", arguments[i]); 
5.         } 
6.       }; 
7.       // how to use 
8.       $.preloadImages("image1.jpg");  
9.       }); 
6. 页面样式切换
1.       $(document).ready(function() {  
2.           $("a.Styleswitcher").click(function() {  
3.               //swicth the LINK REL attribute with the value in A REL attribute  
4.               $('link[rel=stylesheet]').attr('href' , $(this).attr('rel'));  
5.           });  
6.       // how to use  
7.       // place this in your header  
8.         
9.       // the links  
10.   Default Theme  
11.   Red Theme  
12.   Blue Theme  
13.   }); 
7. 列高度相同如果使用了两个CSS列,使用此种方式可以是两列的高度相同。

1.       $(document).ready(function() {  
2.       function equalHeight(group) {  
3.           tallest = 0;  
4.           group.each(function() {  
5.               thisHeight = $(this).height();  
6.               if(thisHeight > tallest) {  
7.                   tallest = thisHeight;  
8.               }  
9.           });  
10.       group.height(tallest);  
11.   }  
12.   // how to use  
13.   $(document).ready(function() {  
14.       equalHeight($(".left"));  
15.       equalHeight($(".right"));  
16.   });  
17.   }); 
8. 动态控制页面字体大小用户可以改变页面字体大小

1.       $(document).ready(function() {  
2.         // Reset the font size(back to default)  
3.         var originalFontSize = $('html').css('font-size');  
4.           $(".resetFont").click(function(){  
5.           $('html').css('font-size', originalFontSize);  
6.         });  
7.         // Increase the font size(bigger font0  
8.         $(".increaseFont").click(function(){  
9.           var currentFontSize = $('html').css('font-size');  
10.       var currentFontSizeNum = parseFloat(currentFontSize, 10);  
11.       var newFontSize = currentFontSizeNum*1.2;  
12.       $('html').css('font-size', newFontSize);  
13.       return false;  
14.     });  
15.     // Decrease the font size(smaller font)  
16.     $(".decreaseFont").click(function(){  
17.       var currentFontSize = $('html').css('font-size');  
18.       var currentFontSizeNum = parseFloat(currentFontSize, 10);  
19.       var newFontSize = currentFontSizeNum*0.8;  
20.       $('html').css('font-size', newFontSize);  
21.       return false;  
22.     });  
23.   }); 

9. 返回页面顶部功能
1.       $(document).ready(function() {  
2.       $('a[href*=#]').click(function() {  
3.        if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')  
4.        && location.hostname == this.hostname) {  
5.          var $target = $(this.hash);  
6.          $target = $target.length && $target  
7.          || $('[name=' + this.hash.slice(1) +']');  
8.          if ($target.length) {  
9.         var targetOffset = $target.offset().top;  
10.     $('html,body')  
11.     .animate({scrollTop: targetOffset}, 900);  
12.       return false;  
13.      }  
14.     }  
15.     });  
16.   // how to use  
17.   // place this where you want to scroll to  
18.     
19.   // the link  
20.   go to top  
21.   }); 
11.获得鼠标指针XY值
1.       $(document).ready(function() {  
2.          $().mousemove(function(e){  
3.            //display the x and y axis values inside the div with the id XY  
4.           $('#XY').html("X Axis : " + e.pageX + " | Y Axis " + e.pageY);  
5.         });  
6.       // how to use  
7.      
  
8.        
9.       }); 
12. 验证元素是否为空
1.       $(document).ready(function() {  
2.         if ($('#id').html()) {  
3.          // do something  
4.          }  
5.       }); 
13. 替换元素
1.       $(document).ready(function() {  
2.          $('#id').replaceWith(' 
3.      
I have been replaced
 
4.       
5.       ');  
6.       }); 
14. jQuery延时加载功能
1.       $(document).ready(function() {  
2.          window.setTimeout(function() {  
3.            // do something  
4.          }, 1000);  
5.       }); 
15. 移除单词功能
1.       $(document).ready(function() {  
2.          var el = $('#id');  
3.          el.html(el.html().replace(/word/ig, ""));  
4.       }); 
16. 验证元素是否存在于Jquery对象集合中
1.       $(document).ready(function() {  
2.          if ($('#id').length) {  
3.         // do something  
4.         }  
5.       }); 
17. 使整个DIV可点击
1.       $(document).ready(function() {  
2.           $("div").click(function(){  
3.             //get the url from href attribute and launch the url  
4.             window.location=$(this).find("a").attr("href"); return false;  
5.           });  
6.       // how to use  
7.      
home
  
8.        
9.       }); 
18.ID与Class之间转换当改变Window大小时,在ID与Class之间切换
1.       $(document).ready(function() {  
2.          function checkWindowSize() {  
3.           if ( $(window).width() > 1200 ) {  
4.               $('body').addClass('large');  
5.           }  
6.           else {  
7.               $('body').removeClass('large');  
8.           }  
9.          }  
10.   $(window).resize(checkWindowSize);  
11.   }); 

19. 克隆对象
1.       $(document).ready(function() {  
2.          var cloned = $('#id').clone();  
3.       // how to use  
4.      
  
5.        
6.       }); 
20. 使元素居屏幕中间位置
1.       $(document).ready(function() {  
2.         jQuery.fn.center = function () {  
3.             this.css("position","absolute");  
4.             this.css("top", ( $(window).height() - this.height() ) / 2+$(window).scrollTop() + "px");  
5.             this.css("left", ( $(window).width() - this.width() ) / 2+$(window).scrollLeft() + "px");  
6.             return this;  
7.         }  
8.         $("#id").center();  
9.       }); 
21. 写自己的选择器
1.       $(document).ready(function() {  
2.          $.extend($.expr[':'], {  
3.              moreThen1000px: function(a) {  
4.                  return $(a).width() > 1000;  
5.             }  
6.          });  
7.         $('.box:moreThen1000px').click(function() {  
8.             // creating a simple js alert box  
9.             alert('The element that you have clicked is over 1000 pixels wide');  
10.     });  
11.   }); 
22. 统计元素个数
1.       $(document).ready(function() {  
2.          $("p").size();  
3.       }); 
23. 使用自己的 Bullets
1.       $(document).ready(function() {  
2.          $("ul").addClass("Replaced");  
3.          $("ul > li").prepend("‒ ");  
4.        // how to use  
5.        ul.Replaced { list-style : none; }  
6.       }); 
24. 引用Google主机上的Jquery类库Let Google host the jQuery script for you. This can be done in 2 ways.


1.       //Example 1  
2.         
3.         
9.        
10.    // Example 2:(the best and fastest way)  
11.    
 25. 禁用Jquery(动画)效果
1.       $(document).ready(function() {  
2.           jQuery.fx.off = true;  
3.       }); 
26. 与其他Javascript类库冲突解决方案
1.       $(document).ready(function() {  
2.          var $jq = jQuery.noConflict();  
3.          $jq('#id').show();  
4.       });  
sql处理 sqlserver
sqlserver 处理:
《一》把数据库中得L,R变成“左边”,“右边”,并进行排序。
select ACS_RDE_ID,ACS_RDE_NAM,INTN_ID,IP_ADD,IF_ADD,
              (case UPPER(ATHD_SDE) when 'L' then '左边' else '右边' end ) as ATHD_SDE,
              ACS_MTH,PIN_SUP,
              (case UPPER(IS_ELEV_RDE) when 'Y' then '是' else '否' end ) as IS_ELEV_RDE, 
              (case UPPER(IS_LKUP) when 'Y' then '是' else '否' end) as IS_LKUP,
              PIN_CMD,RDE_TYP,APB_TYP,APB_TMOT,APB_ACT,ENTY_ID,EXIT_ID,CRT_TIME, CRT_BY, LST_UPD_TIME, LST_UPD_BY, VRSN_ID
        FROM ACS_RDE  
        WHERE 1=1
ORDER BY 
		 cast(parsename(IP_ADD,4) AS INT),
		 cast(parsename(IP_ADD,3) AS INT),
		 cast(parsename(IP_ADD,2) AS INT),
		 cast(parsename(IP_ADD,1) AS INT),  
		 IF_ADD, UPPER(ATHD_SDE)
处理报表 ireport
sqlserver的用法:
《一》case when then 判断事件的状态。时间的处理。
<select id="searchAlarmEventReportByAlarmTimePeriod" resultMap="ResultMap"
		parameterClass="AlarmEventReportParam">
		select (
		case 
			when t.EVT_STAT_ID = '2' and t.ALM_EVT_TYP_ID != 10 then '正常' 
			when t.EVT_STAT_ID = '2' and t.ALM_EVT_TYP_ID =  10 then '设备故障' 
			when t.EVT_STAT_ID = '3' then '误报' 
			else '报警中'  	
			end) as alarmName,
			COUNT(1) as almCount,
			<isEqual property="timePeriodStr" compareValue="yy">
				DATEPART(yy, t.ALM_TIME) AS almTime
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="qq">
				DATEPART(qq, t.ALM_TIME) AS almTime
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="mm">
				DATEPART(mm, t.ALM_TIME) AS almTime
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="wk">
				DATEPART(wk, t.ALM_TIME) AS almTime
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="dd">
				DATEPART(dd, t.ALM_TIME) AS almTime
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="hh">
				DATEPART(hh, t.ALM_TIME) AS almTime
			</isEqual>
				from  ALM_EVT_LOG t, LOV_EVT_STAT s
					 where t.EVT_STAT_ID=s.EVT_STAT_ID
			<isNotNull property="alarmEventTimeFrom" prepend="AND"> 
				t.ALM_TIME >=#alarmEventTimeFrom:DATE#
			</isNotNull>
			<isNotNull property="alarmEventTimeTo" prepend="AND"> 
				t.ALM_TIME <=#alarmEventTimeTo:DATE#
			</isNotNull>
				group by t.ALM_EVT_TYP_ID,
			<isEqual property="timePeriodStr" compareValue="yy">
				DATEPART(yy, t.ALM_TIME),
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="qq">
				DATEPART(qq, t.ALM_TIME),
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="mm">
				DATEPART(mm, t.ALM_TIME),
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="wk">
				DATEPART(wk, t.ALM_TIME),
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="dd">
				DATEPART(dd, t.ALM_TIME),
			</isEqual>
			<isEqual property="timePeriodStr" compareValue="hh">
				DATEPART(hh, t.ALM_TIME),
			</isEqual>
		 		t.EVT_STAT_ID
				order by ALM_EVT_TYP_ID
	</select>

ProcessorImpl.java       《  画出报表 》

public byte[] alarmEventReportByAlarmTimePeriod(
			SearchAlarmEventReportParam searchAlarmEventReportParam)
			throws ErrorInfoException {
		AlarmEventReportParam reportparam=new AlarmEventReportParam();
		reportparam.setAlarmEventTimeFrom(searchAlarmEventReportParam.getAlarmEventTimeFrom());
		reportparam.setAlarmEventTimeTo(searchAlarmEventReportParam.getAlarmEventTimeTo());
		
		if(null==searchAlarmEventReportParam.getTimePeriod()){
			reportparam.setTimePeriod(TimePeriod.HOUR); 
		}else{
			reportparam.setTimePeriod(searchAlarmEventReportParam.getTimePeriod()); 
		}
		List alarmEventList = alarmEventService
				.alarmEventReportByAlarmTimePeriod(reportparam);
		String jasperReportPath = "com/newcross/vsg/platform/template/AlarmEventStatByAlarmTime.jasper";
		Map timemap=new HashMap(); 
		String str = reportparam.getTimePeriodStr();
		String timeStr = "";
		if("yy".equals(str)){
			timeStr="年";
		}else if("qq".equals(str)){
			timeStr="季度";
		}else if("mm".equals(str)){
			timeStr="月";
		}else if("wk".equals(str)){
			timeStr="周";
		}else if("dd".equals(str)){
			timeStr="日";
		}else if("hh".equals(str)){
			timeStr="时";
		}
		timemap.put("alarm", timeStr);
		
		byte[] buffer = null;
		try {
			buffer = ReportUtils.createImage(jasperReportPath, alarmEventList,
					timemap, 1.0f, "png");
			FileOutputStream out = new FileOutputStream("C:/test2.png");
			out.write(buffer);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return buffer;

	}

生成报表条件:
String readerType = "";
		if(null != accessCardReaderParam.getReaderName() &&
                     !"".equals(accessCardReaderParam.getReaderName())){
		    readerType +="读卡器名称=" + accessCardReaderParam.getReaderName()+ ",";
		}
		if(null != accessCardReaderParam.getIpAddress() &&
                    !"".equals(accessCardReaderParam.getIpAddress())){
		  readerType +="IP地址=" + accessCardReaderParam.getIpAddress()+ ",";
		}
		if(null != accessCardReaderParam.getInterfaceAddress() &&
                     !"".equals(accessCardReaderParam.getInterfaceAddress())){
		   readerType += "IF地址=" + accessCardReaderParam.getInterfaceAddress()+ ",";
		}
		if(null != accessCardReaderParam.getAttachedSide() &&
                    !"".equals(accessCardReaderParam.getAttachedSide())){
		  readerType += "设备连接位置=" + accessCardReaderParam.getAttachedSide()+ ",";
		}
		if(readerType.length()>0){
		   reportParam.put("generateFile", readerType.substring(0, readerType.length()-1));
		}else{
		    readerType = "无";
	             reportParam.put("generateFile", readerType);
		}
generateFile是报表里传过来的参数。
wsgen与wsimport命令说明 other
wsgen
wsgen是在JDK的bin目录下的一个exe文件(Windows版),该命令的主要功能是用来生成合适的JAX-WS。它读取Web Service的终端类文件,同时生成所有用于发布WebService所依赖的源代码文件和经过编译过的二进制类文件。这里要特别说明的是,通常在Web ServiceBean中用到的异常类会另外生成一个描述Bean,如果Web ServiceBean中的方法有申明抛出异常,这一步是必需的,否则服务器无法绑定该对像。此外,wsgen还能辅助生成WSDL和相关的xsd文件。wsgen从资源文件生成一个完整的操作列表并验证web service是否合法,可以完整发布。
命令参数说明:

? -cp 定义classpath 
? -r 生成 bean的wsdl文件的存放目录 
? -s 生成发布Web Service的源代码文件的存放目录(如果方法有抛出异常,则会生成该异常的描述类源文件) 
? -d 生成发布Web Service的编译过的二进制类文件的存放目录(该异常的描述类的class文件)

命令范例:wsgen -cp ./bin -r ./wsdl -s ./src -d ./bin -wsdl org.jsoso.jws.server.Example

wsimport
wsimport也是在JDK的bin目录下的一个exe文件(Windows版),主要功能是根据服务端发布的wsdl文件生成客户端存根及框架,负责与Web Service服务器通信,并在将其封装成实例,客户端可以直接使用,就像使用本地实例一样。对Java而言,wsimport帮助程序员生存调用webservice所需要的客户端类文件.java和.class。要提醒指出的是,wsimport可以用于非Java的服务器端,如:服务器端也许是C#编写的web service,通过wsimport则生成Java的客户端实现。
命令参数说明:

? -d 生成客户端执行类的class文件的存放目录 
? -s 生成客户端执行类的源文件的存放目录 
? -p 定义生成类的包名

命令范例:wsimport -d ./bin -s ./src -p org.jsoso.jws.client.ref http://localhost:8080/hello?wsdl


windows xp jdk环境变量 other
windows xp下配置JDK环境变量:     
 1.安装JDK,安装过程中可以自定义安装目录等信息,例如我们选择安装目录为D:\java\jdk1.5.0_08;  
 2.安装完成后,右击“我的电脑”,点击“属性”;      
 3.选择“高级”选项卡,点击“环境变量”;      
 4.在“系统变量”中,设置3项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击“编辑”,不存在则点击“新建”;      
 5.JAVA_HOME指明JDK安装路径,就是刚才安装时所选择的路径D:\java\jdk1.5.0_08,此路径下包括lib,bin,jre等文件夹(此变量最好设置,因为以后运行tomcat,eclipse等都需要依*此变量);            
 Path使得系统可以在任何路径下识别java命令,设为: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin    
 CLASSPATH为java加载类(class or lib)路径,只有类在classpath中,java命令才能识别,设为: 
    .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar (要加.表示当前路径)   
 %JAVA_HOME%就是引用前面指定的JAVA_HOME;        
6.“开始”->;“运行”,键入“cmd”;        
7.键入命令“java -version”,“java”,“javac”几个命令,出现画面,说明环境变量配置成功; 


Win7:
配置好以上环境变量之后,各系统变量的值如下:
JAVA_HOME:C:/Program Files/Java/jdk1.5.0_06 
CATALINA_HOME:D:/jakarta-tomcat-5.0.30 
CLASSPATH:.;%JAVA_HOME%/lib;%CATALINA_HOME%/common/lib; 
Path:%JAVA_HOME%/bin;%CATALINA_HOME%/bin;%SystemRoot%/system32;%SystemRoot%;%

SystemRoot%/System32/Wbem
用dwr,让js调用java中的方法 jquery
1、配置web.xml

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="UTF-8"?>   
02.<web-app version="2.4"    
03.    xmlns="http://java.sun.com/xml/ns/j2ee"    
04.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
05.    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee    
06.    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">   
07.       
08.  
09.  <!-- 配置DWR框架的Servlet -->       
10.  <servlet>   
11.    <servlet-name>dwrServlet</servlet-name>   
12.    <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>   
13.  </servlet>   
14.     
15.  <servlet-mapping>   
16.    <servlet-name>dwrServlet</servlet-name>   
17.    <url-pattern>/dwr/*</url-pattern>   
18.  </servlet-mapping>   
19.       
20.  <welcome-file-list>   
21.    <welcome-file>index.jsp</welcome-file>   
22.  </welcome-file-list>   
23.</web-app>  

2、配置dwr.xml

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="UTF-8"?>  
02.<!DOCTYPE dwr PUBLIC   
03.    "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"   
04.    "http://getahead.org/dwr/dwr20.dtd">  
05.<dwr>  
06.    <!--  配置客户端JS与JAVA类之间的关联关系   -->  
07.    <allow>  
08.        <!-- javascript="user":表示在客户端生成JS的文件名字       
09.             creator:如果为new  表示当前的类是通过new来实例的    
10.             如果为spring:表示当前的JAVA类引用spring中的bean -->  
11.        <create javascript="user" creator="new">  
12.             <!-- param:类的路径配置    
13.                  name:为class的表示配置类路径 (creator="new")   
14.                  如果creator="spring" name为beanName  -->  
15.            <param name="class" value="cn.com.wlz.server.UserServer">  
16.            </param>  
17.            <!-- 可以被客户端调用 的JAVA类中的方法    
18.            <include method="isUser,"/>-->  
19.            <!-- 不可以被客户端调用 的JAVA类中的方法    
20.            <exclude method=""/> -->  
21.        </create>  
22.        <!-- 把JS中的对像转换成对应的JAVA对像   
23.         match:JAVA类路径   converter="bean":告诉DWR   
24.        框架,如果是对像的话,自动进行转换 -->  
25.        <convert match="cn.com.wlz.vo.User" converter="bean"></convert>    
26.    </allow>  
27.</dwr>  

3.java类

view plaincopy to clipboardprint?
01.package cn.com.wlz.server;   
02.  
03.import cn.com.wlz.vo.User;   
04.  
05.public class UserServer {   
06.    //判断用户是否可用      
07.    public int isUser( String name ){      
08.        System.out.println( "name:"+name );      
09.        if(name.equals( "wlz" ))      
10.            return 1;      
11.        return 0;      
12.    }      
13.          
14.//    //用户注册      
15.    public int register( User user ){      
16.              
17.        System.out.println( "username:"+user.getUsername()+"password:"+user.getPassword());      
18.        if( user.getUsername().equals( "wlz" ) )      
19.            return 0;      
20.        return 1;      
21.    }      
22.     
23.}     
   view plaincopy to clipboardprint?
01.package cn.com.wlz.vo;   
02.  
03.public class User {   
04.    private String username;      
05.    private String password;      
06.          
07.    public String getPassword() {      
08.        return password;      
09.    }      
10.    public void setPassword(String password) {      
11.        this.password = password;      
12.    }      
13.    public String getUsername() {      
14.        return username;      
15.    }      
16.    public void setUsername(String username) {      
17.        this.username = username;      
18.    }      
19.  
20.}  
4、jsp代码

view plaincopy to clipboardprint?
01.<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>   
02.<%   
03.    String path = request.getContextPath();   
04.    String basePath = request.getScheme() + "://"  
05.            + request.getServerName() + ":" + request.getServerPort()   
06.            + path + "/";   
07.%>   
08.  
09.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">   
10.<html>   
11.    <head>   
12.        <!-- 导入DWR框架运行的JS文件 -->   
13.        <mce:script type="text/javascript" src="<%=path%><!--   
14./dwr/engine.js">   
15.// --></mce:script>   
16.        <mce:script type="text/javascript" src="<%=path%><!--   
17./dwr/util.js">   
18.// --></mce:script>   
19.  
20.        <!--  导入DWR框架动态生成的JS   调用dwr.xml中通过create javascript设置的JS名字 -->   
21.        <mce:script type="text/javascript" src="<%=path%><!--   
22./dwr/interface/user.js">   
23.// --></mce:script>   
24.    </head>   
25.  
26.    <mce:script type="text/javascript"><!--   
27.     
28.        //验证用户      
29.        function isUser( value ){      
30.            alert( value );      
31.            //通过JS调用JAVA类中的方法  最后一个参数为回调函数,获取返回的值      
32.            user.isUser( value,function(data){      
33.                alert(data);      
34.            });      
35.        }      
36.              
37.        //注册      
38.       function register(){      
39.                  
40.            var user1 = {};      
41.            user1.username = DWRUtil.getValue( "username" );      
42.            user1.password = DWRUtil.getValue( "password" );      
43.            alert( user1.username+user1.password );      
44.            user.register( user1,function(data){      
45.                  
46.                alert(data);      
47.            } );       
48.                  
49.            //alert( "register" );      
50.        }      
51.          
52.       
53.// --></mce:script>   
54.  
55.    <body>   
56.        <center>   
57.            用户名:   
58.            <input name="username" onblur="isUser(this.value)" />   
59.            <br>   
60.            密码:   
61.            <input name="password" />   
62.            <br>   
63.            <input type="button" name="register" onclick="register()"  
64.                value="register" />   
65.    </body>   
66.</html>  

jmesa报表 jmesa
1,需要添加多个jar包,参照jmesa的官方例子。
2,需要将jmesa的官方例子中的css,js,images三个文件夹拷到项目的根目录下,注意发布到tomcat时要将这三个文件夹也拷过去。
具体代码如下:
                    1,jmesaAction
import static org.jmesa.limit.ExportType.JEXCEL;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.StrutsStatics;
import org.jmesa.facade.TableFacade;
import org.jmesa.facade.TableFacadeFactory;
import org.jmesa.limit.Limit;
import org.jmesa.util.ItemUtils;
import org.jmesa.view.component.Column;
import org.jmesa.view.component.Row;
import org.jmesa.view.component.Table;
import org.jmesa.view.editor.BasicCellEditor;
import org.jmesa.view.editor.CellEditor;
import org.jmesa.view.html.HtmlBuilder;
import org.jmesa.view.html.component.HtmlColumn;
import org.jmesa.view.html.component.HtmlRow;
import org.jmesa.view.html.component.HtmlTable;

import com.goodhope.icbc.server.dao.impl.BankDAOHibernate;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class jmesaAction extends ActionSupport {

    private static final long serialVersionUID = 1L;

    private BankDAOHibernate bankDAOHibernate;

    public String execute() throws Exception {
        HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) ActionContext.getContext().get(StrutsStatics.HTTP_RESPONSE);
        List userDetail = bankDAOHibernate.findAll();
        TableFacade tableFacade = TableFacadeFactory.createTableFacade("bank", request);
        tableFacade.setItems(userDetail);
        tableFacade.setExportTypes(response, JEXCEL);
        tableFacade.setStateAttr("restore");
        Limit limit = tableFacade.getLimit();
        if (limit.isExported()) {
            export(tableFacade);
            return null;
        }
        String html = html(tableFacade);
        request.setAttribute("userDetail", html); //这个也可使用set方法。
        return super.execute();
    }
//这里设置页面的展现内容
    private String html(TableFacade tableFacade) {

        tableFacade.setColumnProperties("id", "money", "cardNo", "version");
        HtmlTable table = (HtmlTable) tableFacade.getTable();
        table.setCaption("--用户信息--");
        HtmlRow row = table.getRow();
        HtmlColumn id = row.getColumn("id");
        id.setTitle("id");
        id.setFilterable(false);
        HtmlColumn money = row.getColumn("money");
        money.setTitle("余款");
        HtmlColumn cardNo = row.getColumn("cardNo");
        cardNo.setTitle("卡号");
        HtmlColumn version = row.getColumn("version");
        version.setTitle("版本号");
         //设置超链接
        cardNo.getCellRenderer().setCellEditor(new CellEditor() {
            public Object getValue(Object item, String property, int rowcount) {
                Object value = new BasicCellEditor().getValue(item, property, rowcount);
                HtmlBuilder html = new HtmlBuilder();
                Object cardNo = ItemUtils.getItemValue(item, "cardNo");
                html.a().href().quote().append("http://localhost:8080/icbc-server/LoginAction.html?cardNo=" + cardNo).quote().close();
                html.append(value);
                html.aEnd();
                return html.toString();
            }
        });

        return tableFacade.render();
    }
// 设置导出格式
    private void export(TableFacade tableFacade) {

        tableFacade.setColumnProperties("id", "money", "cardNo", "version");
        Table table = tableFacade.getTable();
        table.setCaption("用户信息表");
        Row row = table.getRow();
        Column id = row.getColumn("id");
        id.setTitle("id");
        Column name = row.getColumn("money");
        name.setTitle("余款");
        Column cardNo = row.getColumn("cardNo");
        cardNo.setTitle("卡号");
        Column version = row.getColumn("version");
        version.setTitle("版本号");

        tableFacade.render();

    }

    public BankDAOHibernate getBankDAOHibernate() {
        return bankDAOHibernate;
    }

    public void setBankDAOHibernate(BankDAOHibernate bankDAOHibernate) {
        this.bankDAOHibernate = bankDAOHibernate;
    }

}

        2,ftl页面:
<html>
<head><title>用华信息</title></head>

<link rel="stylesheet" type="text/css" href="${request.getContextPath()}/css/web.css"></link>
<link rel="stylesheet" type="text/css" href="${request.getContextPath()}/css/jmesa.css"></link>
<link rel="stylesheet" type="text/css" href="${request.getContextPath()}/css/jmesa-pdf.css"></link>
<script type="text/javascript" src="${request.getContextPath() }/js/jmesa.js"></script>
<script type="text/javascript" src="${request.getContextPath() }/js/jquery-1.2.2.pack.js"></script>
<script type="text/javascript" src="${request.getContextPath() }/js/jquery.bgiframe.pack.js"></script>

<body>

    <form name="userDetial" action="${request.getContextPath()}/jmesaAction.html">
           ${userDetail}
    </form>
    

<script type="text/javascript">

    function onInvokeAction(id) {
        setExportToLimit(id, '');
        createHiddenInputFieldsForLimitAndSubmit(id);
    }
    function onInvokeExportAction(id) {
        var parameterString = createParameterStringForLimit(id);
        alert(parameterString);
        location.href = '${request.getContextPath()}/jmesaAction.html?' + parameterString;
    }
   
</script>
</body>
</html>

js编码技巧 javascript
摘要:写任何编程代码,不同的开发者都会有不同的见解。但参考一下总是好的,下面是来自Javascript Toolbox发布的14条最佳JS代码编写技巧。
  写任何编程代码,不同的开发者都会有不同的见解。但参考一下总是好的,下面是来自Javascript Toolbox发布的14条最佳JS代码编写技巧。

  1. 总是使用 var
  在javascript中,变量不是全局范围的就是函数范围的,使用var关键词将是保持变量简洁明了的关键。当声明一个或者是全局或者是函数级(function-level)的变量,需总是前置var关键词,下面的例子将强调不这样做潜在的问题。

  不使用 Var 造成的问题

var i=0; // This is good - creates a global variablefunction test() {   for (i=0; i 10; i++) {      alert("Hello World!");   }}test();alert(i); // The global variable i is now 10!  因为变量函数中变量 i 并没有使用 var 使其成为函数级的变量,在这个例子中它引用了全局变量。总是使用 var 来声明全局变量是一个很多的做法,但至关重要的一点是使用 var 定义一个函数范围的变量。下面这两个方法在功能上是相同的:

  正确的函数

function test() {   var i=0;   for (i=0; i10; i++) {      alert("Hello World!");   }}  正确的函数

function test() {   for (var i=0; i10; i++) {      alert("Hello World!");   }}  2. 特性检测而非浏览器检测
  一些代码是写来发现浏览器版本并基于用户正使用的客户端的对其执行不同行为。这个,总的来说,是一个非常糟的实践。更好的方法是使用特性检测,在使用一个老浏览器可能不支持的高级的特性之前,首先检测(浏览器的)是否有这个功能或特性,然后使用它。这单独检测浏览器版本来得更好,即使你知道它的性 能。你可以在这里找到一个深入讨论这个问题的文章。

  例子:

if (document.getElementById) {   var element = document.getElementById('MyId');}else {   alert('Your browser lacks the capabilities required to run this script!');}  3. 使用方括号记法
  当访问由执行时决定或者包括要不能用.号访问的对象属性,使用方括号记法。如果你不是一个经验丰富的Javascript程序员,总是使用方括号是一个不错的做法。

  对象的属性由两种固定的方法来访问:.记法和[ ]方括号记法:

  .号记法

MyObject.property  [ ]方括号记法

MyObject["property"]  使用.号,属性名是硬代码,不能在执行时改变。使用[ ]方括号,属性名是一个通过计算属性名而来的字符串。字符串要以是硬代码,也可能是变量,甚至可以是一个调回一个字母串值的函数。 如果一个属性名在执行产生,方括号是必须,如果你有 value1″, value2″, 和 value3″这样的属性,并且想利用变量 i=2来访问

  这个可以运行:

MyObject["value"+i]  这个不可以:

MyObject.value+i  并且在某些服务器端环境(PHP、Struts等)下,Form 表单被附加了 [ ] 号来表示 Form 表单在服务器端必须被当作数组来对待。如此,用.号来引用一个包含 [ ] 号的字段将不会执行,因为 [ ] 是引用一个 Javascript 数组的语法。所以,[ ] 号记法是必须的:

  这个可以运行:

formref.elements["name[]"]  这个不可以:

formref.elements.name[]  推荐使用[ ]方括号记法是说当其需要时(明显地)总是使用它。当不是严格需要使用它的时候,它是一个私人的偏好和习惯。一个好的经验原则是,使用.号记法访问标准的对象属性,使用[ ]方括号记法访问由页面定义的对象属性。这样,document["getElementById"]() 是一个完美可行的[ ]方括号记法用法,但 document.getElementById() 在语法上是首选,因为 getElementById 是一个 DOM 规范中定义的一个标准文档对象属性。混合使用这两个记法使哪个是标准对象属性,哪个属性名是由上下文所定义的,在代码中显得清晰明了:

document.forms["myformname"].elements["myinput"].value  这里,forms 是 document 的一个标准属性,而表单名 myformname 则是由页面所定义的。同时,elements 和 value 属性都是由规范所定义的标准属性。而 myinput 则是由页面所定义的。这页是句法让人非常容易理解(代码的内容),是一个推荐遵循的习惯用法,但不是严格原则。

  4. 避免 eval
  在Javascript中,eval()功能是一个在执行期中执行任意代码的方法。在几乎所有的情况下,eval 都不应该被使用。如果它出现在你的页面中,则表明你所做的有更好的方法。举一个例子,eval 通常被不知道要使用方括号记法的程序员所使用。

原则上,Eval is evil(Eval是魔鬼)。别使用它,除非你是一个经验丰富的开发者并且知道你的情况是个例外。

  5. 正确地引用表单和表单元素
  所有的 html 表单都应该有一个 name 属性。对于 XHTML 文档来说,name 属性是不被要求的,但 Form 标签中应有相应有 id 属性,并必须用 document.getElementById() 来引用。使用像 document.forms[0] 这样的索引方法来引用表单,在几乎所有情况下,是一个糟糕的做法。有些浏览器把文档中使用 form 来命名的元素当作一个可用的 form 属性。这样并不可靠,不应该使用。

  下面这个例子用使用方括号和正确的对象引用方法来展示如何防止错误地引用一个表单的input:

  正确引用表单 Input:

document.forms["formname"].elements["inputname"]  糟糕的做法:

document.formname.inputname  如果你要引用一个函数里的两个表单元素,较好的做法是先引用这个form对象,并将其储存在变量中。这样避免了重复查询以解决表单的引用:

var formElements = document.forms["mainForm"].elements;formElements["input1"].value="a";formElements["input2"].value="b";  当你使用 onChange 或者其他类似的事件处理方法,一个好的做法是总是通过一个引来把 input 元素本身引用到函数中来。所有 input 元素都带有一个对包含其在内的Form表单有一个引用:

input type="text" name="address" onChange="validate(this)"function validate(input_obj) {// 引用包含这个元素的formvar theform = input_obj.form;// 现在你可以不需要使用硬代码来引用表单自身if (theform.elements["city"].value=="") {alert("Error");}}  通过对表单元素的引用来访问表单的属性,你可以写一个不包含硬代码的函数来引用这个页面中任何一个有特定名的表单。这是一个非常好的做法,因为函数变得可重用。

  避免 with
  Javascript 中的 with 声明在一个作用域的前端插入一个对象,所以任何属性/变量的引用将会倚着对象被首先解决。这通常被用作一个避免重复引用的快捷方法:

  使用 with 的例子:

with (document.forms["mainForm"].elements) {   input1.value = "junk";   input2.value = "junk";}  但问题在于程序员并没有方法来验证 input1 或 input2 实际上已经被当作 Form 元素数组的属性来解决。它首先以为这些名来检测属性,如果找不到,它将会继续(向下)检测这个作用域。最后,它在全局对象中尝试把input1 和 input2 作为一个全局对象来对待,而这以一个错误作为结尾。

  变通的方法是:创建一个引用来减少引用的对象,并使用它来解决这些引用。

  使用一个引用:

var elements = document.forms["mainForm"].elements;elements.input1.value = "junk";elements.input2.value = "junk";  7. 在锚点中使用 onclick 替代 javascript: Pseudo-Protocol
  如果你想在 a 标签中触发Javascript 代码,选择 onclick 而非 JavaScript: pseudo-protocol;使用 onclick 来运行的 Javascript 代码必须返回 ture 或者false(or an expression than evalues to true or false [这句要怎么翻译呢? 我是这样理解的:一个优先性高于true 或 false 的表达式])来返回标签本身:如果返回 true,则锚点的 href 将被当作一个一般的链接;如果返回 false,则 href 会被忽略。这就是为什么return false; 经常被包含在 onclick 所处理代码的尾部。

  正确句法:

a href="javascript_required.html"go/a  在这个实例中,doSomething() 函数(定义于页面的某个角落)将在被点击时调用。href 将永远不会被启用了Javascript 的浏览器访问。在你可以提醒Javascript 是必须的、而用户未启用之的浏览器中,文档 javascript_required.html 才会被加载。通常,当你确保用户将会开启 Javascript 支持,为尽量简化,链接将只包含 href=#。 而这个做法是不被鼓励的。通常有一个不错的做法是:可以提供没用启用 javascript 一个返回本地的页面。

有时,众多想要分情况来访问一个链接。例如,当一个用户要离开你的一个表单页面,而想先验证来确保没有东西被改变。在这个情况下,你的 onclick 将会访问一个返回询问链接是否应该被遵循的函数:

  有条件的链接访问:

a href="/"Home/afunction validate() {return prompt("Are you sure you want to exit this page?");}  在这个实例中,validate() 函数必须只返回 ture 或 false。ture 的时候用户将被允许问题 home 页面,或 false 的时候链接不被访问。这个例子提示确认(其行为),以访问 ture 或 false,这完全由用户点击确实或者取消决定。

  下面是一些不应该的例子。如果你在自己的页面中看到下面这样的代码,这是不正确的,需要被修改:

  什么是不应该做的:

a href="javascript:doSomething()"link/aa href="#"link/aa href="#"link/aa href="#"link/a  8. 使用一元 + 号运算符使类型转向Number
  在Javascript中,+号运算符同时充当数学加号和连接符。这会在form表单的域值相加时出现问题,例如,因为Javascript是 一个弱类型语言,form 域的值将会被当作数组来处理,而你把它们+一起的时候,+将被当成连接符,而非数学加号。

  有问题的例子:

form name="myform" action="[url]"input type="text" name="val1" value="1"input type="text" name="val2" value="2"/formfunction total() {var theform = document.forms["myform"];var total = theform.elements["val1"].value + theform.elements["val2"].value;alert(total); // 这个将会弹出 "12", 但你想要的是 3!}  解决这个问题,Javascript 需要一个提示来让它把这些值当做数字来处理。你可以使用+号来把数组转换成数字。给变量或者表达式前置一个+号将会强制其当作一个数字来处理,而这也将使得数学+得以成功应用。

  修改好的代码:

function total() { var theform = document.forms["myform"]; var total = (+theform.elements["val1"].value) + (+theform.elements["val2"].value); alert(total); // This will alert 3}  9. 避免 document.all
  document.all 是由Microsoft 的 IE 所引进的,并不是一个标准的 Javascript DOM 特性。尽管大多数新的浏览器支持它以支持依赖于它的糟糕代码,(而)还有很多浏览器是不支持的。

  并没有理由其他方法都不适用,而一个老的IE浏览器(5.0)需要支持,而在Javascript中使用 document.all 作为一个折衷方法。 你并不需要使用 document.all 来检测其是不是IE浏览器,因为其他浏览器现在一般都支持。

  只把 document.all 当做最后的选择:

if (document.getElementById) { var obj = document.getElementById("myId");}else if (document.all) { var obj = document.all("myId");}  一些使用 document.all 的原则:

•同尝试其他方法
•当其作为最后的选择
•当需要支持 5.0 版本以下的 IE 浏览器
•总是使用 if (document.all) { } 来查看是否支持.
  10. 不要在脚本代码块中使用HTML注释
  在 Javascript 的旧日子(1995)里,诸如 Netscape 1.0 的一些浏览器并不支持或认识 script 标签。所以,当 Javascript 第一次被发布,需要有一个技术来让实些代码不被当做文本显示于旧版浏览器上。有一个hack 是在代码中使用 HTML 注释来隐藏这些代码。

  使 HTML 注释并不好:

script language="javascript"!--   // code here//--/script  在今天,没有任何一个常用的浏览器会忽略掉 script 标签。因此,再没必要隐藏 Javascript 源代码。事实上,它还可以因为下面的理由,被认为是无益的:

•在 XHTML 文档中,源代码将向所有浏览器隐藏并被渲染成无用的(内容);
•– 在 HTML 注释并不允许 ,这个会让任何递减操作将失效。
  11. 避免乱用全局命名空间
  一般很少需要全部变量和函数。全局使用将可能导致 Javascript 源文件文档冲突,和代码中止。因此,一个好的做法是在一个全局命名空间内采用函数性的封装。有多个方法可以完成这个任务,有此相对比较复杂。最简单的方法 是创建一个全局对象,并把属性和方法指派给这个对象:

  创建一个命名空间:

var MyLib = {}; // global Object cointainerMyLib.value = 1;MyLib.increment = function() { MyLib.value++; }MyLib.show = function() { alert(MyLib.value); }MyLib.value=6;MyLib.increment();MyLib.show(); // alerts 7  命名空间也可以使用 Closures(闭包?) 来创建,并且 Private Member Variables (私有变量?) 也可以伪装于 Javascript中。

  12. 避免同步的 ajax 调用
  当使用Ajax请求时,你要么选择异步模式,要么使用同步模式。当浏览器行为可以继续执行,异步模式将请求放在后台执行,同步模式则会等待请求完成后才继续。

  应该避免同步模式做出的请求。这些请求将会对用户禁用浏览器,直至请求返回。一旦服务器忙,并需要一段时间来完成请求,用户的浏览器(或者 OS)将不能做任何其他的事,直至请求超时。

  如果你觉得自己的情况需要同步模式,最大的可能是你需要时间来重新想一下你的设计。很少(如果有的话)实际上需要同步模式的 Ajax 请求。

  13. 使用 JSON
  当需要将数据结构存储成纯文本,或者通过 Ajax 发送/取回数据结构,尽可能使用 JSON 代替 XML。JSON (JavaScript Object Notation) 是一个更简洁有效的数据存储格式,并且不依赖任何语言(and is a language-neutral)。

  14. 使用正确的 script 标签
  不造成在 script 中的使用LANGUAGE 属性。一个合适的方式是创建如下的 Javascript 代码块: 

<script type="text/javascript">// code here</script>
如何判断javaScript对象是否存在 javascript
  Javascript语言的设计不够严谨,很多地方一不小心就会出错。

  举例来说,请考虑以下情况。

  现在,我们要判断一个全局对象myObj是否存在,如果不存在,就对它进行声明。用自然语言描述的算法如下:

  if (myObj不存在){

    声明myObj;

  }

  你可能会觉得,写出这段代码很容易。但是实际上,它涉及的语法问题,远比我们想象的复杂。Juriy Zaytsev指出,判断一个Javascript对象是否存在,有超过50种写法。只有对Javascript语言的实现细节非常清楚,才可能分得清它们的区别。

  第一种写法

  根据直觉,你可能觉得可以这样写:

  if (!myObj){

    myObj = {};

  }

  但是,运行这段代码,浏览器会直接抛出ReferenceError错误,导致运行中断。请问错在哪里?

  对了,if语句判断myObj是否为空时,这个变量还不存在,所以才会报错。改成下面这样,就能正确运行了。

  if (!myObj){

    var myObj = {};

  }

  为什么加了一个var以后,就不报错了?难道这种情况下,if语句做判断时,myObj就已经存在了吗?

  要回答这个问题,就必须知道Javascript解释器的工作方式。Javascript语言是"先解析,后运行",解析时就已经完成了变量声明,所以上面的代码实际等同于:

  var myObj;

  if (!myObj){

    var myObj = {};

  }

  因此,if语句做判断时,myObj确实已经存在了,所以就不报错了。这就是var命令的"代码提升"(hoisting)作用。Javascript解释器,只"提升"var命令定义的变量,对不使用var命令、直接赋值的变量不起作用,这就是为什么不加var会报错的原因。

  第二种写法

  除了var命令,还可以有另一种改写,也能得到正确的结果:

  if (!window.myObj){

    myObj = {};

  }

  window是javascript的顶层对象,所有的全局变量都是它的属性。所以,判断myobj是否为空,等同于判断window对象是否有myobj属性,这样就可以避免因为myObj没有定义而出现ReferenceError错误。不过,从代码的规范性考虑,最好还是对第二行加上var:

  if (!window.myObj){

    var myObj = {};

  }

  或者写成这样:

  if (!window.myObj){

    window.myObj = {};

  }

  第三种写法

  上面这种写法的缺点在于,在某些运行环境中(比如V8、Rhino),window未必是顶层对象。所以,考虑改写成:

  if (!this.myObj){

    this.myObj = {};

  }

  在全局变量的层面中,this关键字总是指向顶层变量,所以就可以独立于不同的运行环境。

  第四种写法

  但是,上面这样写可读性较差,而且this的指向是可变的,容易出错,所以进一步改写:

  var global = this;

  if (!global.myObj){

    global.myObj = {};

  }

  用自定义变量global表示顶层对象,就清楚多了。

  第五种写法

  还可以使用typeof运算符,判断myObj是否有定义。

  if (typeof myObj == "undefined"){

    var myObj = {};

  }

  这是目前使用最广泛的判断javascript对象是否存在的方法。

  第六种写法

  由于在已定义、但未赋值的情况下,myObj的值直接等于undefined,所以上面的写法可以简化:

  if (myObj == undefined){

    var myObj = {};

  }

  这里有两个地方需要注意,首先第二行的var关键字不能少,否则会出现ReferenceError错误,其次undefined不能加单引号或双引号,因为这里比较的是undefined这种数据类型,而不是"undefined"这个字符串。

  第七种写法

  上面的写法在"精确比较"(===)的情况下,依然成立:

  if (myObj === undefined){

    var myObj = {};

  }

  第八种写法

  根据javascript的语言设计,undefined == null,所以比较myObj是否等于null,也能得到正确结果:

  if (myObj == null){

    var myObj = {};

  }

  不过,虽然运行结果正确,但是从语义上看,这种判断方法是错的,应该避免。因为null指的是已经赋值为null的空对象,即这个对象实际上是有值的,而undefined指的是不存在或没有赋值的对象。因此,这里只能使用"比较运算符"(==),如果这里使用"精确比较运算符"(===),就会出错。

  第九种写法

  还可以使用in运算符,判断myObj是否为顶层对象的一个属性:

  if (!('myObj' in window)){

    window.myObj = {};

  }

  第十种写法

  最后,使用hasOwnProperty方法,判断myObj是否为顶层对象的一个属性:

  if (!this.hasOwnProperty('myObj')){

    this.myObj = {};

  }

  总结

  1. 如果只判断对象是否存在,推荐使用第五种写法。

  2. 如果除了对象是否存在,还要判断对象是否有null值,推荐使用第一种写法。

  3. 除非特殊情况,所有变量都应该使用var命令声明。

  4. 为了跨平台,建议避免使用window表示顶层对象。

  5. 在Javascript语言中,null和undefined容易产生混淆。在可能同时涉及两者的情况下,建议使用"精确比较"运算符(===)。

JSON json
如果你跟我一样(我担心你就是),那么,到目前为止,这应该是你对JSON的经验:

1.两个月前你从没听说过JSON
2.一个月前你听说了这个词但没有留意
3.一周前你发现这个词被提到多次,开始想,没错 又有一些垃圾东西要学了
4.今天你被心灵深处的一个闹铃闹醒,心想:这该死的json究竟是个什么东西?为什么突然间到处都是它了!
  于是晚上我乘坐了一辆慢腾腾的公交回到家(周五通常都是很慢),然后给自己找了一大堆关于JSON资料。所以我可以文雅的带你进入JSON的大门。

  这就开始了 

  这几个字母是什么意思?
  JavaScript Object Notation.

  [一个滑稽的名字。它应该被称作Lightweight Ecmascript Object Notation, 或简称 'LEON'。 ]

  它是个什么东西?
  JSON是一种传递对象的语法,对象可以是name/value对,数组和其他对象。

  下面是一小段JSON代码:

{"skillz": {"web":[{"name": "html", "years": "5"},{"name": "css", "years": "3"}],"database":[{"name": "sql", "years": "7"}]}}  你看懂了吧?那么当你再看到它时就知道它是JSON了。主要部分:

  花括弧,方括弧,冒号和逗号
1.花括弧表示一个容器
2.方括号装载数组
3.名称和值用冒号隔开
4.数组元素通过逗号隔开
  把它想成得了厌食症的XML
  (如果你跟我一样老,可以把它想成有层次关系的.INI文件)

  (如果你是个自以为是的Lisp小丑,可以把它想成S-expressions,自以为是吧)

  JSON很像XML,因为:
1.他们都自我描述,这意味着值都是可列举的,是人类可读的
2.都是有层级的。(例如你可以在值里再存放值)
3.都能被多种的编程语言解析和使用
4.都能使用AJAX方法来传递(例如httpWebRequest)
  JSON跟XML不一样,因为:
1.XML里在元素的开始和结尾处有尖括号和标签名:JSON使用花括号,而且只在数据的开始和结束时使用。
2.JSON更简练,毫无疑问更适合人类书写,也许也能让我们更快速的阅读。
3.JSON可以在JavaScript里简单的传递到eval()方法里使用
4.JSON里有数组{每个元素没有自己的名称}
5.在XML里你可以对一个元素使用任意想要的名称,在JSON里你不能使用Javascript里的保留字
  可是为什么?它有什么好的?
  当你写ajax之类的东西时,如果你使用JSON,你就勉去了手工拼写XML。更迅速。

  同样,当你写ajax之类的东西时,怎样最简单?XML方式还是JSON方式:

XML方式:
1.取回一个XML文件
2.循环它,从中提取值
3.处理这些值,等
对比
JSON方式:
1.取回JSON字符串。
2.eval JSON数据
  它是面向对象的吗?
  No,严格的说,不是。

  就像是VB6里的面向对象一样。它提供了很好的封装机制,你可以使用它把数据和方法分离出来,但它不提供任何的继承,多型,接口,或其它类似的面向对象的东西

  很显然,它是使javascript变得更易于维护,分析和复用的方向上前进了一步。

  Thomas Frank写了一个灵巧的javascript库,叫做classyJSON,它在JSON代码上增加了继承和定义范围等特征。

  它只是用在客户端吗?
  是,也不是。在服务器端你可以容易的把对象序列化成JSON或反之。对于.net,程序员可以使用类似Json.net的类库使这些操作自动化(我估计是使用反射机制),或你使用自己的程序来做这些事,可能会更快些。

  3分钟将近结束.
  就我所知,JSON是由一个叫做Douglas Crockford的家伙发明的。如果你喜欢的话,可以看一下他的网站,他非常的有趣。

  现在去读一下懂JSON的人写的东西
  (从Delicious using JSON上搜刮来的!)

•DOM Query Speed Test
•24 ways: Dont be eval()
•Understanding JSON: the 3 minute lesson
•Serializing Objects as JavaScript using Atlas, JSON.NET and AjaxPro
•JSON – Wikipedia, the free encyclopedia
•Introduction to JSON
•XML.com: JSON and the Dynamic Script Tag: Easy, XML-less Web Services for JavaScript
•Classy JSON
•ajax json tutoral
•XML to JSON – a converter
  这就是全部。
  我在几分钟的时间里只能整理出这些东西所有我说的有些东西可能完全是错的。如果是这样,请留言告诉我,告诉我我有多傻。我会很高兴的纠正任何一个错误。祝你好运!

  (边注:如果你把 { 和 } 替换成 和 /,把: 换成 / 你会得到一个非常像gaXml的东西。有趣的世界。

  (边注2:Jason 和 Ajax 都是希腊神话中的英雄。预告:另外一些即将出现的技术垃圾包括:Heracles, Perseus, Deucalion, Theseus and Bellerophon。)

标签: JSON JavaScript    相关文章:
JavaScript重构之JavaScript的测试
如何判断Javascript对象是否存在
14条最佳JS代码编写技巧
仿新浪微博返回顶部的js实现(jQuery/MooTools)
Javascript中的对象查找

读取文件 other
// 从文件中获取key
    File f = new File("C:\\RMC.certificate");
    InputStream in = new FileInputStream(f);
    byte b[] = new byte[(int) f.length()]; // 创建合适文件大小的数组
    in.read(b); // 读取文件中的内容到b[]数组
    in.close();
    String licensekey = new String(b).substring(
	new String(b).indexOf("license.key="),
	new String(b).length());
    System.out.println(licensekey);
    String key_key = key.substring(key.indexOf("=") + 1,
    key.length());
    System.out.println(key_key);
js跳转,下载权限 other
比如在注册的action中,当用户名已存在时如何在return INPUT的同时在页面上弹出一个提示信息给用户知道
,可以在request中携带参数,在页面javaScript中用EL表达式或者JAVA接收并判断参数 提示信息
例如:
action:
request.setAttribute("param",'1');
javascript:
window.onload=function(){//页面加载事件
  var paramStr = "<%=request.getAttribute("param") %>";//这里是接收参数也可以用EL表达式: var paramStr = "${requestScope.param}";
  if(paramStr == '1'){
    alert("提示信息");
}
}

下面用一个简单的验证下载权限的例子
页面(有jquery支持)JS:

  $.post("下载权判断.action",{"url":url,"username":"猪头"},function(date){  
          if(date.map.ok){
              //可以下载,启动下载  相关代码
          }else{
              alert(date.map.msg);
          }
     }, "json");
struts2配置:

<action name="下载权判断" class="Action" method="下载权判断方法"><result type="json" /></action>

Action.java:

public class Action{
private Map<String, Object> map = new HashMap<String, Object>();
private String username;
private String url;

public String 下载权判断方法(){
if("猪头".equals(username)){
map.put("ok",true);
map.put("msg","你是猪头可以下载");
}else{
map.put("ok",false);
map.put("msg","你不是猪头不可以下载");
}
return "success";
}

public void setUsername(String username) {
		this.username= username;
	}
public void setUrl(String url) {
		this.url= url;
	}

//map的get,set  .....必须
	@JSON
	public Map<String, Object> getMap() {
		return map;
	}
	public void setMap(Map<String, Object> map) {
		this.map = map;
	}
}

先异步发送请求过去,然后成功了。再返回成功信息后,就跳转另一个页面;在action中发生错误时,就页面提示错误,不跳页面
文件上载 other
Oracle ADF框架是用struts来作为其Controller的。为了与Oracle ADF的ADF Bindings配合使用,Oracle开发了自己的动态的formbean——oracle.adf.controller.struts.forms.BindingContainerActionForm。它的实现类似于org.apache.struts.action.DynaActionForm。但与DynaActionForm不同的是,DynaActionForm是从struts-config.xml配置文件中读取各个属性及其类型;而BindingContainerActionForm是从ADF Bindings配置文件并通过查找对应View的配置文件而读取各个属性及其类型。因此《怎样在web应用中上载文件》一文中所讲述的使用struts内置文件上传功能的方法,在使用BindingContainerActionForm时不奏效了。

通过下面的步骤,可以在ADF 框架下实现Web应用文件的上载:


1. 在Model工程中,找到对应的View并增加OrdDocDomain类型的属性。



    如上图所示,本例增加了FileAttr属性,其类型是OrdDocDomain。



    2. 编辑需要选择文件上载的界面,本例是editDept.jsp。从Data Control Palette窗口中选择FileAttr,并把Drag and Drop as设置为File Input Filed。将FileAttr拖拽到jsp界面上。




    这一步实际上是在jsp文件中增加File Input框,以及在bindings中指明所绑定的View的属性。

   做完了这一步,jsp中增加了以下代码:

      <P>

         <html:file property="FileAttr"/>

      </P>

 

  Binding配置文件中增加了以下配置:

      <DCControl

         id="FileAttr"

         SubType="DCTextField"

         IterBinding="DeptView1Iterator"

         ApplyValidation="false"

         isDynamic="false" >

         <AttrNames>

            <Item Value="FileAttr" />

         </AttrNames>

      </DCControl>


 


3. 在action的某个方法中处理上载的文件

DCBindingContainer bindings = actionContext.getBindingContainer();

        binding = bindings.findCtrlBinding("FileAttr");//得到FileAttr属性

        OrdDocDomain file = (OrdDocDomain)binding.get("FileAttr");

        

        InputStream stream = file.getDataInStream();//获取其InputStream

        OutputStream bos = new FileOutputStream("D:/ttttttt");

        int bytesRead = 0;

        byte[] buffer = new byte[8192];

        while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {

            bos.write(buffer, 0, bytesRead);

        }

        bos.close();

        stream.close();   

        

        Row currentRow=binding.getCurrentRow();//清除View Cache中的文件内容

        currentRow.setAttribute("FileAttr",null);


 

 


 



 


通过上面几个步骤,文件上载的功能就算做好了。

在ADF框架下开发的Web文件上载功能,其真正处理文件上载的还是org.apache.struts.upload.CommonsMultipartRequestHandler ,只是由于使用的是BindingContainerActionForm而非Struts的DynaActionForm或标准的ActionForm(继承ActionForm,实现各个属性的get/set方法) 。因而,处理完上载的文件后,BindingContainerActionForm会根据binding的配置以及View的配置,将文件的内容附值给View的对应的oracle.ord.im.OrdDocDomain类型的属性(注意:不是org.apache.struts.upload.FormFile类型)。我们只需获得该属性的内容,保存为文件即可。

需要注意的是:保存完文件之后,需要把Veiw 离线Cache中的已上传并保存的内容置空。否则,如果紧接着在相同页面上载文件的话,新上载的文件内容就被叠加进上一次上载的文件内容中,即相当于把两个文件合并了。下面两句,即是置空内容的方法:

        Row currentRow=binding.getCurrentRow();

        currentRow.setAttribute("FileAttr",null);


 



 


到此为止,文件是可以上传了。可是程序却不好好工作,时不时报出这样的错误:

org.apache.struts.upload.CommonsMultipartRequestHandler handleRequest

严重: Failed to parse multipart request

org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Read timed out

       at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:429)

       at org.apache.struts.upload.CommonsMultipartRequestHandler.handleRequest(CommonsMultipartRequestHandler.java:233)

       at org.apache.struts.util.RequestUtils.populate(RequestUtils.java:1209)

       at org.apache.struts.action.RequestProcessor.processPopulate(RequestProcessor.java:821)

       at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:254)

       at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1485)

       at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:527)

       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)

       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)


       at com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilterChain.java:65)

at oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)

      at com.evermind.server.http.EvermindFilterChain.doFilter(EvermindFilterChain.java:16)

    at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:239)

      at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:645)

   at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:322)

    at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:790)

      at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:270)

   at com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:112)

   at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:192)

       at java.lang.Thread.run(Thread.java:534)

 

对于比较小的文件还好些,对于大些的文件,几乎一上传就报这种错误。这又是怎么一回事呢?


 


后来终于在Oracle网站上找到了答案,原来是Embedded OC4J 的HTTP活动超时限制的时间太短的缘故,文件还没有上传完毕,就超时了。(同样运行在Embedded OC4J环境下,这个错误在使用文章《怎样在web应用中上载文件》所介绍的方法时没有发生过)。所以如果你要传输比较大的文件的时候,需要把这个值设置得大些,开始我把原值由500毫秒(0.5秒)变成了5000毫秒(5秒),发现还是经常超时,于是就干脆设置成50000毫秒(50秒),上传文件终于没有问题了(你还可以设置的更大些J)。

设置方法如下,在JDeveloper 10.1.2菜单中Tools  -> Embedded OC4J Server Preferences… -> Global  -> HTTP Keep-Alive Timeout.



消息框提醒 html
提示框:
<html>
<head>
<script type="text/javascript">
function disp_prompt()
  {
  var name=prompt("请输入您的名字","Bill Gates")
  if (name!=null && name!="")
    {
    document.write("你好!" + name + " 今天过得怎么样?")
    }
  }
</script>
</head>
<body>

<input type="button" onclick="disp_prompt()" value="显示提示框" />

</body>
</html>

警告框:
<html>
<head>
<script type="text/javascript">
function disp_alert()
{
alert("我是警告框!!")
}
</script>
</head>
<body>

<input type="button" onclick="disp_alert()" value="显示警告框" />

</body>
</html>

带有折行警告框:
<html>
<head>
<script type="text/javascript">
function disp_alert()
{
alert("再次向您问好!在这里,我们向您演示" + '\n' + "如何向警告框添加折行。")
}
</script>
</head>
<body>

<input type="button" onclick="disp_alert()" value="显示警告框" />

</body>
</html>

确认框:
<html>
<head>
<script type="text/javascript">
function show_confirm()
{
var r=confirm("Press a button!");
if (r==true)
  {
  alert("You pressed OK!");
  }
else
  {
  alert("You pressed Cancel!");
  }
}
</script>
</head>
<body>

<input type="button" onclick="show_confirm()" value="Show a confirm box" />

</body>
</html>
Hibernate优化 hibernate
Hibernate的优化 
: Ø         数据库设计调整 Ø         HQL优化 Ø         API的正确使用(如根据不同的业务类型选用不同的集合及查询API) Ø         主配置参数(日志,查询缓存,fetch_size, batch_size等) Ø         映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化) Ø         一级缓存的管理 Ø         针对二级缓存,还有许多特有的策略 Ø         事务控制策略。 1、 数据库设计 a)         降低关联的复杂性 b)        尽量不使用联合主键 c)        ID的生成机制,不同的数据库所提供的机制并不完全一样 d)   ... 

Spring security配置实例 spring
Spring security配置实例

4,来看看authentication-provider的实现:
package com.robin.erp.fwk.security;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class MyUserDetailService implements UserDetailsService {

     @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException, DataAccessException {
         Collection<GrantedAuthority> auths=new ArrayList<GrantedAuthority>();
         GrantedAuthorityImpl auth2=new GrantedAuthorityImpl("ROLE_ADMIN");
         auths.add(auth2);
        if(username.equals("robin1")){
             auths=new ArrayList<GrantedAuthority>();
             GrantedAuthorityImpl auth1=new GrantedAuthorityImpl("ROLE_ROBIN");
             auths.add(auth1);
         }
        
//         User(String username, String password, boolean enabled, boolean accountNonExpired,
//                     boolean credentialsNonExpired, boolean accountNonLocked, Collection<GrantedAuthority> authorities) {
         User user = new User(username,
                "robin", true, true, true, true, auths);
        return user;
     }
    
}在这个类中,你就可以从数据库中读入用户的密码,角色信息,是否锁定,账号是否过期等,我想这么简单的代码就不再多解释了。

5,对于资源的访问权限的定义,我们通过实现FilterInvocationSecurityMetadataSource这个接口来初始化数据。
package com.robin.erp.fwk.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.AntUrlPathMatcher;
import org.springframework.security.web.util.UrlMatcher;


/**
* 
* 此类在初始化时,应该取到所有资源及其对应角色的定义
* 
* @author Robin
* 
*/
public class MyInvocationSecurityMetadataSource
        implements FilterInvocationSecurityMetadataSource {
    private UrlMatcher urlMatcher = new AntUrlPathMatcher();;
    private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

    public MyInvocationSecurityMetadataSource() {
         loadResourceDefine();
     }

    private void loadResourceDefine() {
         resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
         Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
         ConfigAttribute ca = new SecurityConfig("ROLE_ADMIN");
         atts.add(ca);
         resourceMap.put("/index.jsp", atts);
         resourceMap.put("/i.jsp", atts);
     }

    // According to a URL, Find out permission configuration of this URL.
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        // guess object is a URL.
         String url = ((FilterInvocation)object).getRequestUrl();
         Iterator<String> ite = resourceMap.keySet().iterator();
        while (ite.hasNext()) {
             String resURL = ite.next();
            if (urlMatcher.pathMatchesUrl(url, resURL)) {
                return resourceMap.get(resURL);
             }
         }
        return null;
     }

    public boolean supports(Class<?> clazz) {
        return true;
     }
    
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
     }

}
看看loadResourceDefine方法,我在这里,假定index.jsp和i.jsp这两个资源,需要ROLE_ADMIN角色的用户才能访问。
这个类中,还有一个最核心的地方,就是提供某个资源对应的权限定义,即getAttributes方法返回的结果。注意,我例子中使用的是AntUrlPathMatcher这个path matcher来检查URL是否与资源定义匹配,事实上你还要用正则的方式来匹配,或者自己实现一个matcher。

6,剩下的就是最终的决策了,make a decision,其实也很容易,呵呵。
package com.robin.erp.fwk.security;
import java.util.Collection;
import java.util.Iterator;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;


public class MyAccessDecisionManager implements AccessDecisionManager {

    //In this method, need to compare authentication with configAttributes.
    // 1, A object is a URL, a filter was find permission configuration by this URL, and pass to here.
    // 2, Check authentication has attribute in permission configuration (configAttributes)
    // 3, If not match corresponding authentication, throw a AccessDeniedException.
    public void decide(Authentication authentication, Object object,
             Collection<ConfigAttribute> configAttributes)
            throws AccessDeniedException, InsufficientAuthenticationException {
        if(configAttributes == null){
            return ;
         }
         System.out.println(object.toString());  //object is a URL.
         Iterator<ConfigAttribute> ite=configAttributes.iterator();
        while(ite.hasNext()){
             ConfigAttribute ca=ite.next();
             String needRole=((SecurityConfig)ca).getAttribute();
            for(GrantedAuthority ga:authentication.getAuthorities()){
                if(needRole.equals(ga.getAuthority())){  //ga is user's role.
                    return;
                 }
             }
         }
        throw new AccessDeniedException("no right");
     }

     @Override
    public boolean supports(ConfigAttribute attribute) {
        // TODO Auto-generated method stub
        return true;
     }

     @Override
    public boolean supports(Class<?> clazz) {
        return true;
     }


}
在这个类中,最重要的是decide方法,如果不存在对该资源的定义,直接放行;否则,如果找到正确的角色,即认为拥有权限,并放行,否则throw new AccessDeniedException("no right");这样,就会进入上面提到的403.jsp页面。

 

Spring Security(用户登录) spring Spring Security应用实例(一):用户登录
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(10) NOT NULL auto_increment,
  `login_name` varchar(20) default NULL,
  `password` varchar(20) default NULL,
  `name` varchar(20) default NULL,
  `email` varchar(30) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Spring web Security3.0体验 spring Spring Web Security3.0 初体验
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/security.xml</param-value>
	</context-param>

	<!-- listener setting-->
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>
			org.springframework.web.filter.DelegatingFilterProxy
		</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
Java线程总结 线程
首先要理解线程首先需要了解一些基本的东西,我们现在所使用的大多数操作系统都属于多任务,分时操作系统。正是由于这种操作系统的出现才有了多线程这个概念。我们使用的windows,linux就属于此列。什么是分时操作系统呢,通俗一点与就是可以同一时间执行多个程序的操作系统,在自己的电脑上面,你是不是一边听歌,一边聊天还一边看网页呢?但实际上,并不上cpu在同时执行这些程序,cpu只是将时间切割为时间片,然后将时间片分配给这些程序,获得时间片的程序开始执行,不等执行完毕,下个程序又获得时间片开始执行,这样多个程序轮流执行一段时间,由于现在cpu的高速计算能力,给人的感觉就像是多个程序在同时执行一样。 
一般可以在同一时间内执行多个程序的操作系统都有进程的概念.一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间,一组系统资源.在进程概念中,每一个进程的内部数据和状态都是完全独立的.因此可以想像创建并执行一个进程的系统开像是比较大的,所以线程出现了。在java中,程序通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务.多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行.(你可以将前面一句话的程序换成进程,进程是程序的一次执行过程,是系统运行程序的基本单位) 

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈.所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,正因如此,线程也被称为轻负荷进程(light-weight process).一个进程中可以包含多个线程. 

多任务是指在一个系统中可以同时运行多个程序,即有多个独立运行的任务,每个任务对应一个进程,同进程一样,一个线程也有从创建,运行到消亡的过程,称为线程的生命周期.用线程的状态(state)表明线程处在生命周期的哪个阶段.线程有创建,可运行,运行中,阻塞,死亡五中状态.通过线程的控制与调度可使线程在这几种状态间转化每个程序至少自动拥有一个线程,称为主线程.当程序加载到内存时,启动主线程. 

[线程的运行机制以及调度模型] 
java中多线程就是一个类或一个程序执行或管理多个线程执行任务的能力,每个线程可以独立于其他线程而独立运行,当然也可以和其他线程协同运行,一个类控制着它的所有线程,可以决定哪个线程得到优先级,哪个线程可以访问其他类的资源,哪个线程开始执行,哪个保持休眠状态。 
下面是线程的机制图: 


线程的状态表示线程正在进行的活动以及在此时间段内所能完成的任务.线程有创建,可运行,运行中,阻塞,死亡五中状态.一个具有生命的线程,总是处于这五种状态之一: 
1.创建状态 
使用new运算符创建一个线程后,该线程仅仅是一个空对象,系统没有分配资源,称该线程处于创建状态(new thread) 
2.可运行状态 
使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于可运行状态(Runnable) 
3.运行中状态 
Java运行系统通过调度选中一个Runnable的线程,使其占有CPU并转为运行中状态(Running).此时,系统真正执行线程的run()方法. 
4.阻塞状态 
一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态(Blocked) 
5.死亡状态 
线程结束后是死亡状态(Dead) 

同一时刻如果有多个线程处于可运行状态,则他们需要排队等待CPU资源.此时每个线程自动获得一个线程的优先级(priority),优先级的高低反映线程的重要或紧急程度.可运行状态的线程按优先级排队,线程调度依据优先级基础上的"先到先服务"原则. 
线程调度管理器负责线程排队和CPU在线程间的分配,并由线程调度算法进行调度.当线程调度管理器选种某个线程时,该线程获得CPU资源而进入运行状态. 

线程调度是先占式调度,即如果在当前线程执行过程中一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行.先占式调度分为:独占式和分时方式. 
独占方式下,当前执行线程将一直执行下去,直 到执行完毕或由于某种原因主动放弃CPU,或CPU被一个更高优先级的线程抢占 
分时方式下,当前运行线程获得一个时间片,时间到时,即使没有执行完也要让出CPU,进入可运行状态,等待下一个时间片的调度.系统选中其他可运行状态的线程执行 
分时方式的系统使每个线程工作若干步,实现多线程同时运行 

另外请注意下面的线程调度规则(如果有不理解,不急,往下看): 
①如果两个或是两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的(Synchronized),如果对象更新影响到只读方法,那么只度方法也应该定义为同步的 
②如果一个线程必须等待一个对象状态发生变化,那么它应该在对象内部等待,而不是在外部等待,它可以调用一个被同步的方法,并让这个方法调用wait() 
③每当一个方法改变某个对象的状态的时候,它应该调用notifyAll()方法,这给等待队列的线程提供机会来看一看执行环境是否已发生改变 
④记住wait(),notify(),notifyAll()方法属于Object类,而不是Thread类,仔细检查看是否每次执行wait()方法都有相应的notify()或notifyAll()方法,且它们作用与相同的对象 在java中每个类都有一个主线程,要执行一个程序,那么这个类当中一定要有main方法,这个man方法也就是java class中的主线程。你可以自己创建线程,有两种方法,一是继承Thread类,或是实现Runnable接口。一般情况下,最好避免继承,因为java中是单根继承,如果你选用继承,那么你的类就失去了弹性,当然也不能全然否定继承Thread,该方法编写简单,可以直接操作线程,适用于单重继承情况。至于选用那一种,具体情况具体分析。 


eg.继承Thread 

public class MyThread_1 extends Thread{public void run(){//some code }} 


eg.实现Runnable接口 

public class MyThread_2 implements Runnable{public void run(){//some code }} 


当使用继承创建线程,这样启动线程: 

new MyThread_1().start() 


当使用实现接口创建线程,这样启动线程: 

new Thread(new MyThread_2()).start() 


注意,其实是创建一个线程实例,并以实现了Runnable接口的类为参数传入这个实例,当执行这个线程的时候,MyThread_2中run里面的代码将被执行。 
下面是完成的例子: 


public class MyThread implements Runnable{ public void run(){ System.out.println("My Name is "+Thread.currentThread().getName()); } public static void main(String[] args){new Thread(new MyThread()).start(); }} 


执行后将打印出: 
My Name is Thread-0 

你也可以创建多个线程,像下面这样 

new Thread(new MyThread()).start();new Thread(new MyThread()).start();new Thread(new MyThread()).start(); 


那么会打印出: 
My Name is Thread-0 
My Name is Thread-1 
My Name is Thread-2 

看了上面的结果,你可能会认为线程的执行顺序是依次执行的,但是那只是一般情况,千万不要用以为是线程的执行机制;影响线程执行顺序的因素有几点:首先看看前面提到的优先级别 


public class MyThread implements Runnable{ public void run(){ System.out.println("My Name is "+Thread.currentThread().getName()); } public static void main(String[] args){Thread t1=new Thread(new MyThread());Thread t2=new Thread(new MyThread());Thread t3=new Thread(new MyThread());t2.setPriority(Thread.MAX_PRIORITY);//赋予最高优先级t1.start();t2.start();t3.start();}} 


再看看结果: 
My Name is Thread-1 
My Name is Thread-0 
My Name is Thread-2 


线程的优先级分为10级,分别用1到10的整数代表,默认情况是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等价与t2.setPriority(10) 
然后是线程程序本身的设计,比如使用sleep,yield,join,wait等方法(详情请看JDKDocument) 


public class MyThread implements Runnable{ public void run(){ try{int sleepTime=(int)(Math.random()*100);//产生随机数字,Thread.currentThread().sleep(sleepTime);//让其休眠一定时间,时间又上面sleepTime决定//public static void sleep(long millis)throw InterruptedException (API)System.out.println(Thread.currentThread().getName()+" 睡了 "+sleepTime);}catch(InterruptedException ie)//由于线程在休眠可能被中断,所以调用sleep方法的时候需要捕捉异常{ie.printStackTrace();} } public static void main(String[] args){Thread t1=new Thread(new MyThread());Thread t2=new Thread(new MyThread());Thread t3=new Thread(new MyThread());t1.start();t2.start();t3.start();}} 


执行后观察其输出: 

Thread-0 睡了 11 
Thread-2 睡了 48 
Thread-1 睡了 69 


上面的执行结果是随机的,再执行很可能出现不同的结果。由于上面我在run中添加了休眠语句,当线程休眠的时候就会让出cpu,cpu将会选择执行处于runnable状态中的其他线程,当然也可能出现这种情况,休眠的Thread立即进入了runnable状态,cpu再次执行它。 
[线程组概念] 
线程是可以被组织的,java中存在线程组的概念,每个线程都是一个线程组的成员,线程组把多个线程集成为一个对象,通过线程组可以同时对其中的多个线程进行操作,如启动一个线程组的所有线程等.Java的线程组由java.lang包中的Thread——Group类实现. 
ThreadGroup类用来管理一组线程,包括:线程的数目,线程间的关系,线程正在执行的操作,以及线程将要启动或终止时间等.线程组还可以包含线程组.在Java的应用程序中,最高层的线程组是名位main的线程组,在main中还可以加入线程或线程组,在mian的子线程组中也可以加入线程和线程组,形成线程组和线程之间的树状继承关系。像上面创建的线程都是属于main这个线程组的。 
借用上面的例子,main里面可以这样写: 


public static void main(String[] args){/***************************************ThreadGroup(String name) ThreadGroup(ThreadGroup parent, String name) ***********************************/ThreadGroup group1=new ThreadGroup("group1");ThreadGroup group2=new ThreadGroup(group1,"group2");Thread t1=new Thread(group2,new MyThread());Thread t2=new Thread(group2,new MyThread());Thread t3=new Thread(group2,new MyThread());t1.start();t2.start();t3.start();} 


线程组的嵌套,t1,t2,t3被加入group2,group2加入group1。 
另外一个比较多就是关于线程同步方面的,试想这样一种情况,你有一笔存款在银行,你在一家银行为你的账户存款,而你的妻子在另一家银行从这个账户提款,现在你有1000块在你的账户里面。你存入了1000,但是由于另一方也在对这笔存款进行操作,人家开始执行的时候只看到账户里面原来的1000元,当你的妻子提款1000元后,你妻子所在的银行就认为你的账户里面没有钱了,而你所在的银行却认为你还有2000元。 
看看下面的例子: 


class BlankSaving //储蓄账户{private static int money=10000;public void add(int i){money=money+i;System.out.println("Husband 向银行存入了 [¥"+i+"]");}public void get(int i){money=money-i;System.out.println("Wife 向银行取走了 [¥"+i+"]");if(money<0)System.out.println("余额不足!"); }public int showMoney(){return money;}} class Operater implements Runnable{String name;BlankSaving bs;public Operater(BlankSaving b,String s){name=s;bs=b;}public static void oper(String name,BlankSaving bs){if(name.equals("husband")){try{for(int i=0;i<10;i++){Thread.currentThread().sleep((int)(Math.random()*300));bs.add(1000);}}catch(InterruptedException e){}}else{try{for(int i=0;i<10;i++){Thread.currentThread().sleep((int)(Math.random()*300));bs.get(1000);}}catch(InterruptedException e){}}}public void run(){oper(name,bs);} }public class BankTest {public static void main(String[] args)throws InterruptedException{BlankSaving bs=new BlankSaving();Operater o1=new Operater(bs,"husband");Operater o2=new Operater(bs,"wife");Thread t1=new Thread(o1);Thread t2=new Thread(o2);t1.start();t2.start();Thread.currentThread().sleep(500);}} 


下面是其中一次的执行结果: 


---------first-------------- 
Husband 向银行存入了 [¥1000] 
Wife 向银行取走了 [¥1000] 
Wife 向银行取走了 [¥1000] 
Husband 向银行存入了 [¥1000] 
Wife 向银行取走了 [¥1000] 
Husband 向银行存入了 [¥1000] 
Wife 向银行取走了 [¥1000] 
Husband 向银 
io流总结 凌风雪雕的博客
Java IO的一般使用原则: 
一、按数据来源(去向)分类: 
1、是文件: FileInputStream, FileOutputStream, FileReader, FileWriter 
2、是byte[]:ByteArrayInputStream, ByteArrayOutputStream 
3、是Char[]: CharArrayReader, CharArrayWriter 
4、是String: StringBufferInputStream, StringReader, StringWriter 
5、网络数据流:InputStream, OutputStream, Reader, Writer 
二、按是否格式化输出分: 
1、要格式化输出:PrintStream, PrintWriter 
三、按是否要缓冲分: 
1、要缓冲:BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter 
四、按数据格式分: 
1、二进制格式(只要不能确定是纯文本的): InputStream, OutputStream及其所有带Stream结束的子类 
2、纯文本格式(含纯英文与汉字或其他编码方式);Reader, Writer及其所有带Reader, Writer的子类 
五、按输入输出分: 
1、输入:Reader, InputStream类型的子类 
2、输出:Writer, OutputStream类型的子类 
六、特殊需要: 
1、从Stream到Reader,Writer的转换类:InputStreamReader, OutputStreamWriter 
2、对象输入输出:ObjectInputStream, ObjectOutputStream 
3、进程间通信:PipeInputStream, PipeOutputStream, PipeReader, PipeWriter 
4、合并输入:SequenceInputStream 
5、更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader 
6、对象序列号 java.io.Serializable接口支持将一个Java技术对象存放到一个流中。 
决定使用哪个类以及它的构造进程的一般准则如下(不考虑特殊需要): 
第一,考虑最原始的数据格式是什么:是否为文本? 
第二,是输入还是输出? 
第三,是否需要转换流:InputStreamReader, OutputStreamWriter? 
第四,数据来源(去向)是什么:文件?内存?网络? 
第五,是否要缓冲:bufferedReader (特别注明:一定要注意的是readLine()是否有定义,有什么比read, write更特殊的输入或输出方法) 
第六,是否要格式化输出:print?
Spring AOP中三种实现方式 对Spring AOP中三种实现方式的总结

aop:
1: 编程式:
  其中,必须先自己从spring中已有的adivce或pointcut advistor中继承或实现一个类,然后再通过代理(ProxyFactoryBean)中配置业务对象的接口(proxyInterfaces),业务对象的实现(target),及要向业务对象中织入(weave)的拦截器(interceptorNames),从而完成对一个业务对象的方法的拦截。
  在使用时,从(applicationContext)中查找相应的代理对象,从而实现其拦截的目的。

2: 基于XML schema:
   可以定义一个拦截对象,无需继承或实现任何接口,在applicationContext.xml中配置相应的内容(aop:config)即可
   <aop:config>
     <aop:pointcut id="point别名" expression="execution(返回值 被拦截的类包名或方法(方法参数)"/>
     <aop:aspect id="aspect别名" ref="自定义的拦截对象名称">
       <aop:before pointcut-ref="point别名" method="自定义拦截对象中实施切入的方法名"/>
     </aop:aspect>
   </aop:config>
  
pointcut 表达式  


3:基于annoation:
 主要是利用org.aspectj.lang.annotation包下的Before,AfterReturning,Around,Aspect等类来实现在自定义类中,通过在类声明前加(@Aspect)表明是继承advice,并在指定的方法中前声明pointcut表达式,在 context.xml中配置<aop:aspectj-autoproxy/>,这样,在容器加载bean后,Spring就会自动取得 Annotation信息,进行代理对象建立等   
Spring IoC控制反转总结 Spring IoC控制反转总结

    IoC(Inversion of Control)经常称为控制反转或是依赖注入(Dependence Injection)。通俗的讲就是若需要在具体的应用程序中需要创建一个对象的话,我们不用自己去通new方法生成需要的对象,而是通过spring程序包提供的bean工厂为我们生产这样的一个对象。
    在IoC模式下,应用程序不负责创建对象,但是需要描述创建它们的方式。采用IoC在具体的程序代码中不直接与对象和服务连接,但需要在配置文件中描述哪一个组件需要哪一项服务,由容器负责将这些联系在一起。
    关于spring之IoC常见问题点的分析总结:
    1、工厂方法模式与IoC的实现方面差异。
    IoC 采用配置文件来获取具体目标对象的实现,提高了改变要选择的目标对象的灵活性。在工厂方法模式中,会出现以硬编码方式出现目标对象的实现类(采用可配置化的工厂类可以避免硬编码,但是也会带来额外的维护负担)。Spring框架会对IoC的XML配置文件中的各个配置项目进行解析,然后利用Java的“反射”技术,根据在XML配置文件中给出的类名生成相应名称的类对象实例。另外,工厂方法在组件类的实现形式和对象实例的产生模式等方面也存在一定的缺陷。
    2、是否所有的对象都交给IoC来生产。
    如果需要将组件交给spring管理那就用ioc,如果不想让spring管理那可以随时new。换言之,如果组件会经常修改采用IoC比较好,改变较少用new。一般是在组件出现重用、或用到外部资源的时候,开始考虑使用IoC。
    3、 IoC主要的优点缺点分析。
    优点分析:因为把对象生成放在了XML里定义,所以当需要换一个实现子类将会变的比较简单(一般这样的对象都是基于某种接口实现的),只需要修改XML就可以了,这样可以实现对象的“热插拨”效果,也会方便测试及配置维护。
    缺点分析:(1)生成一个对象的步骤变复杂了(基于IDE的支撑操作逐渐变得简单),不习惯该方式的话,会觉得有点别扭与不直观。(2)因为对象的创建是采用的反射机制,所以在效率上有些损耗(经SUN改良优化后,用反射方式来生成对象和一般new对象的方式,在速度方面的差异在逐步减小)。但相对于IoC提高的维护性和灵活性来说,这点损耗可以忽略不记,除非在对某对象的生成在效率方面要求特别苛刻例外。(3)在IDE进行重构操作的支持较差,如果对类进行改名等操作,还需要手动修改去XML文件之间的匹配关系,属于采用XML方式的不便之处。
    Spring通过控制反转(IoC)促进了松耦合。当应用了 IoC,一个对象依靠的其它对象会通过被动的方式传送进来,而不是这个对象自己创建或者查找依靠对象。不是对象从容器中查找依靠,而是容器在对象初始化时不等对象请求就主动将依靠传送给它。阅网认为IOC更适合理解为一种设计模式。一方面可以理解为控制权的转移:由传统的在程序中控制依赖转移到由容器来控制;另外是依赖注入:将相互依赖的对象进行分离、解耦合,在Spring配置文件中描述他们之间的依赖关系,他们的依赖关系只在使用的时候才建立。
	
	
Spring AOP总结 Spring AOP总结
 
   Spring AOP(Aspect Oriented Programming)
  
   应用程序通常包含两种代码:一是核心业务代码,一是和业务关系不大的代码如日志、事物处理等。
   AOP的思想就是使这两种代码分离,从而降低了两种代码的偶合性,达到了易于重用和维护的目的。
   AOP和OOP:
   在AOP里,每个关注点的实现并不知道是否有其他关注点关注它,这是AOP和OOP的主要区别,
   在AOP里组合的流向是从横切关注点到主关注点,在OOP中组合流向是从主关注点到横切关注点。
   AOP和OOP所关注的对象不同,AOP是OOP有益的补充,不是对立面。
  
   AOP的3个关键概念:
   1:切入点:(PiontCut)
     连接点(Jion piont):是指程序运行中的某个阶段,如方法的调用、异常的抛出等。
     PiontCut就是Jion piont点的集合,它是程序中需要注入的Advice的集合。指明Advice
     在什么 条件下才被触发。
   2:通知(Advice):
          某个连接点采用的处理逻辑,也就是向连接点注入的代码。
   3:Advisor
      是PiontCut和Advice的配置器,它包含PiontCut和Advice,是把Advice注入到PiontCut位置的代码。


   Spring 的3种切入点的实现:
   1:静态切入点:
     静态切入点只限于给定的方法和目标类。不考虑方法的参数。
   2:动态切入点:
     动态切入点不仅限于给定的方法和目标类,还可以指定方法的参数。
     动态切入点有很大的性能损耗,一般很少使用。
   3:自定义切入点:
    正在发展
   
   
   Spring 的通知:
   1:Interception Around通知
  
    Interception Around在Jion Point的前后执行。实现Interception Around通知要实现
    MethodInterceptor接口,示例代码如下:
(1)Logger logger=Logger.getLogger(this.getClass().getName());

public Object invoke(MethodInvocation arg0) throws Throwable {
   // TODO Auto-generated method stub
   logger.log(Level.INFO,arg0.getArguments()[0]+"开始审核数据:");
   Object result=arg0.proceed();
   logger.log(Level.INFO,arg0.getArguments()[0]+"审核数据结束!");
  
   return result;
}

(2)
   /* public class LoginInterceptor implements MethodInterceptor{
     public Object invoke(MenthodInvocation invocation) throws Throwable{
      System.out.println("开始审核数据");
      Object result = invocation.proceed();
      System.out.println("审核数据结束");
      return result;
     }
    }*/

   2:Before通知
(1)通过log4j.properties实现
Logger logger=Logger.getLogger(this.getClass().getName());

public void before(Method arg0, Object[] arg1, Object arg2)
    throws Throwable {
   // TODO Auto-generated method stub
   logger.log(Level.INFO,arg1[0]+"开始数据操作:");

}
   (2):
      Before通知在JiontPoint的前执行。实现Befored通知要实现
    MethodBeforeAdvice接口,示例代码如下:
    public class LoginBeforeAdvice implements MethodBeforeAdvice{
     public void before(Menthod m,Object [] atgs,Object target) throws Throwable{
      System.out.println("开始审核数据");
     }
    }
   
   
   3:After Return 通知
  
    After Return通知在JiontPoint后执行。实现After Returnd通知要实现
    AfterReturningAdvice接口,示例代码如下:
    public class LoginAfterAdvice implements AfterReturningAdvice{
     public void afterReturning(Method m,Object [] atgs,Object target) throws Throwable{
      System.out.println("审核数据结束");
     }
    }
  
   4:Throw通知
(1)Logger logger=Logger.getLogger(this.getClass().getName());
public void afterThrowing(Method arg1, Object[] arg2,Object arg3,Throwable subclass ) throws Throwable{
   System.out.println(arg2[0]+"审核数据异常");
}
  
    Throw通知在JiontPoint抛出异常时执行。实现Throw通知要实现
    ThrowsAdvice接口,示例代码如下:
    public class LoginThrowAdvice implements ThrowsAdvice{
     public void afterThrowing(Method arg1, RemoteException ex) throws Throwable{
      System.out.println("审核数据异常");
     }
    }
  
   5:Introduction 通知
  
   Introduction通知在JiontPoint 调用完毕后执行。实现Introduction通知要实现
    IntroductionAdvisor接口和IntroductionInterceptor接口。
  
用ProxyFactoryBean创建AOP代理
      使用org.springfamework.aop.framework.ProxyFactoryBean是创建AOP代理的基本方式。
  
   1:使用ProxyFactoryBean代理目标类中的所有方法(参考代码:workspace20070228\SpringAOP1)
    示例代码:
    <beans>
    <bean id="log" class="logAround"/>
    <bean id="logBefore" class="logBefore"/>
    <bean id="logAfter" class="logAfter"/>
    <bean id="logThrow" class="logThrow"/>
    <bean id="timebook" class="TimeBook"/>
    <!-设定代理类-->
    <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
    <!--代理的是接口-->
    <property name="proxyInterfaces">
    <value>TimeBookInterface</value>
    </property>
      <!--要代理的目标类-->
    <property name="target">
    <ref bean="timebook"/>
    </property>
    <!--程序中的Advice-->
    <property name="interceptorNames">
    <list>
    <value>logBefore</value>
    <value>logAfter</value>
    <value>logThrow</value>
    </list>
    </property>
    </bean>
    </beans>
  
  
   2:使用ProxyFactoryBean代理目标类中的指定方法
  
    示例代码:
    <beans>
    <bean id="log" class="logAround"/>
    <bean id="logBefore" class="logBefore"/>
    <bean id="logAfter" class="logAfter"/>
    <bean id="logThrow" class="logThrow"/>
    <bean id="timebook" class="TimeBook"/>
    <!--代理目标类的指定方法-->
    <bean id ="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
    <ref bean="log"/>
    </property>
    <!--指定要代理的方法-->
    <property name="patterns">
    <value>.*doCheck.*</value>
    </property>
    </bean>
    <!-设定代理类-->
    <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
   
      <!--要代理的目标类-->
    <property name="target">
    <ref bean="timebook"/>
    </property>
    <!--程序中的Advice-->
    <property name="interceptorNames">
    <list>
    <value>logAdvisor</value>
    </list>
    </property>
    </bean>
    </beans>
   
    ---------------------------------------------------------
   
   正则表达式:
   1:.表示可以匹配任何一个字符
   2:[]表示只有[]里指定的字符才能匹配
   3:*表示匹配次数
   4:?表示可以匹配1或0次
   5:\是正则表达式的连接符
  
   ---------------------------------------------------------------
   Spring 中两种AOP代理方式
   1:动态代理
   动态代理是指代理的是接口,Spring默认的是动态代理
   2:CGLIB代理
   <beans>
   <bean id="log" class="logAround"/>
   <bean id="logBefore" class="logBefore"/>
   <bean id="logAfter" class="logAfter"/>
   <bean id="logThrow" class="logThrow"/>
   <bean id="timebook" class="TimeBook"/>
   <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="proxyTargetClass">
   <value>true</value>
   </property>
   <property name="target">
   <ref bean="timebook"/>
   </property>
   <property name="interceptorNames">
   <list>
   <value>logBefore</value>
   <value>logAfter</value>
   <value>logThrow</value>
   </list>
   </property>
   </bean>
   </beans>
  
-----------------------------------------------------------------------
Spring 中的自动代理方式

自动代理可以跨越多个类,不管哪个类中的方法只要符合要求都可以代理
<beans>
<bean id="log" class="logAround"/>
<bean id="logBefore" class="logBefore"/>
<bean id="logAfter" class="logAfter"/>
<bean id="logThrow" class="logThrow"/>
<bean id="timebook" class="TimeBook"/>
<bean id="timework" class="TimeWork"/>
<!--使用自动代理-->
<bean id="autoProxy" class ="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="logBeforAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="logBefore"/>
</property>
<property name="patterns">
<value>.*do.*</value>
</property>
</bean>
</beans>

------------------------------------------------------------
Spring中的事务处理

   事务处理是由多个步骤组成,这些步骤之间有一定的逻辑关系,作为一个整体的操作过程,所有的步骤必须同时成功或失败。
   1:提交 当所有的操作步骤都被完整执行后,称为该事物被提交。
   2:回滚 由于某个操作失败,导致所有的步骤都没被提交则事物必须回滚,回到事物执行前的状态。
  
   事务的特性:
   ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durablity)
  
   Spring中的事务处理是基于动态AOP机制的实现。
  
   1:编程式事务处理:
  
   spring 提供的TransactionTemplate能够以编程的方式实现事务控制。
  
   HelloADO.java:
    private DataSource dataSource;
    private PlatformTransactionManager transactionManager;
    public int create(String msg){
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
    TransactionStatus status = transactionManager.getTransaction(def);
  
    try{
     JdbcTemplate jt = new JdbcTemplate(dataSource);
     int i=jt.update("insert into st(name,password) values('zz','zz')");
     return i;
    }catch (Exception e){
     transactionManager.rollback(status);
     return 0;
    }
    finally {
     transactionManager.commit(status);
    }
    }
   applicationContext.xml
  
    <beans>
    <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="url">
    <value>jdbc:mysql://localhost:3306/newdb</value>
    </property>
    <property name="username">
    <value>root</value>
    </property>
    <property name="password">
    <value>lxl</value>
    </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource">
    <ref bean="dataSource"/>
    </property>
    </bean>
    <bean id="helloDAO" class ="HelloDAO">
    <property name="dataSource">
    <ref bean="dataSource"/>
    </property>
    <property name="transactionManager">
    <ref bean="transactionManager"/>
    </property>
    </bean>
    </beans>
  
   2:声明式事务处理:
  
   HelloADO.java:
  
    public class HelloDAO {
    private DataSource dataSource ;
    private JdbcTemplate jdbcTemplate;
    public void setDataSource(DataSource dataSource) {
     this.dataSource = dataSource;
     jdbcTemplate = new JdbcTemplate(dataSource);
    }
    public void create(String name){
     jdbcTemplate.update("insert into st(name,password)values('lxl','lxl')");
    }
    }
   applicationContext.xml
    <beans>
    <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName">
    <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="url">
    <value>jdbc:mysql://localhost:3306/newdb</value>
    </property>
    <property name="username">
    <value>root</value>
    </property>
    <property name="password">
    <value>lxl</value>
    </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource">
    <ref bean="dataSource"/>
    </property>
    </bean>
    <bean id="helloDAO" class ="HelloDAO">
    <property name="dataSource">
    <ref bean="dataSource"/>
    </property>
    </bean>
    <!-- 声明式事务处理-->
    <bean id="helloDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager">
    <ref bean="transactionManager"/>
    </property>
    <property name="target">
    <ref bean="helloDAO"/>
    </property>
    <property name="transactionAttributes">
    <props>
    <!-- 对create方法进行事务管理,PROPAGATION_REQUIRED表示如果没有事务就新建一个事务-->
    <prop key="create*">PROPAGATION_REQUIRED</prop>
    </props>
    </property>
    </bean>  
    </beans>
	
Struts国际化处理 Struts国际化处理
Struts国际化处理一
一、Struts的国际化
    Struts是一种支持国际化的MVC的Web Framework。可是如何来使用struts国际化是一个问题。下面我们来探讨一下,如何实现Struts的国际化。Web程式的国际化涉及到3个层面的东西。第一、jsp部分的输入/输出;第二、应用处理程序的国际化;第三、DB的国际化问题。这里主要探讨的是jsp部分的输入/输出问题。
二、静态部分的国际化
   Struts的jsp页面静态内容(包括静态文字,静态图片)国际化问题,是通过资源文件来实现的。要实现国际化,需要做如下几项工作:1、定义 web.xml的动ActionServlet的参数;2、定义资源文件;3、定义JSP页面的字符集合;4、在JSP页面获取资源文件里面的内容。
1、定义web.xml的动ActionServlet的参数
<servlet>
  <servlet-name>action</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>   
  <init-param>
    <param-name>config</param-name>
    <param-value>/WEB-INF/struts-config.xml</param-value>
  </init-param>
  <init-param>
    <param-name>application</param-name>
    <param-value>ApplicationResources</param-value> <!-- 默认资源文件名 -->
  </init-param>
  <load-on-startup>2</load-on-startup>
</servlet>
2、定义资源文件
在/WEB-INF/classes下面添加UTF-8资源束文件。每一个资源文件是“键-值”对的集合。在JSP页面里面可以通过键来找到相应的数据值。本例子的文件名是ApplicationResources,所以相应的资源文件束是(包括e文,简体中文,繁体中文)
ApplicationResources.properties : 默认资源文件。当在其他资源文件里面找不到某个资源的时候,就使用该资源文件里面的定义。
ApplicationResources_zh_CN.properties:简体中文资源文件。
ApplicationResources_zh_TW.properties:繁体中文资源文件。
资源文件的格式为:默认资源文件名_国别_语言.properties。其中每个文件都是通过%JAVA_HONE%/BIN/native2ascii.exe工具转换而来。你也可以使用其他工具来处理得到(http://java.sun.com/products/jilkit/有一个工具Internationalization Java Internationalization and Localization Toolkit 可以处理)。下面是一个例子,我们显示如何使用%JAVA_HONE%/BIN/native2ascii.exe命令来定义资源束文件。
2.1 准备文件
//ApplicationResources.properties ;默认资源文件,通常里面的内容是英文的。
label.username=USERNAME :
label.password=PASSWORD :
//ApplicationResources_zh_CN.bak ;简体中文的资源文件。里面的内容是中文的。它需要工具将其中的内容处理成UTF-8
label.username=用户名 :
label.password=密 码 :
//ApplicationResources_zh_TW.bak : 繁体中文的资源文件。里面的内容是中文的。它需要工具将其中的内容处理成UTF-8,下面的内容是繁体码。
label.username=ノめ?W :
label.password=ノめ?W :
2.2 准备完成以后,使用如下的命令创建UTF-8资源文件束
native2ascii -encoding gb2312 ApplicationResources_zh_CN.bak ApplicationResources_zh_CN.properties
native2ascii -encoding big5 Applica tionResources_zh_TW.bak ApplicationResources_zh_TW.properties
3、定义JSP页面的字符集合
定义JSP页面的语言为UTF-8。在每个JSP页面,必须有如下的内容(如果使用的模板技术,则只是需要在模板页面添加,其他使用该模板的页面无需添加)
<%@ page contentType="text/html;charset=UTF-8"%>
4、在JSP页面获取资源文件里面的内容。
在JSP里面需要显示静态内容的地方使用<bean:message />strus的bean tag包里面的message标签。例如下面的页面
<table>
  <tr>
    <td align="right"><bean:message key="label.username" /></td>   
  </tr>
  <tr>
    <td align="right"><bean:message key="label.password" /></td>
  </tr>
</table>
好了,在这个页面显示的时候,如果客户的IE的语言集合是zh_CN的话,就会显示
用户名:
口 令:
如果是客户的IE的语言是zh_TW的话,就会显示
用户名:
用户名:
可以在IE的工具->Internet选项->语言的地方,来选择,定义IE的语言。
三、表单的数据的处理。
对于表单数据的处理,我们是通过添加一个Filter来实现的。所有提交的请求,都需要做字符处理。然后在web.xml里面定义该Filter。这样我们就不需要在程序里面做任何的字符处理。
3.1 定义Filter。下面是一个例子。
package com.webapps.commons;
import java.io.*;
import javax.servlet.*;
public class CharsetEncodingFilter implements Filter{
  private FilterConfig config = null;
  private String defaultEncode = "UTF-8";
  public void init(FilterConfig config) throws ServletException {
    this.config = config;
    if(config.getInitParameter("Charset")!=null){
        defaultEncode=config.getInitParameter("Charset");
    }
  }
  public void destroy() {
    this.config = null;
  }
  public void doFilter(ServletRequest request, ServletResponse response,
                       FilterChain chain) throws IOException, ServletException {
    ServletRequest srequest=request;
    srequest.setCharacterEncoding(defaultEncode);
    chain.doFilter(srequest,response);
  }
}
3.2 在web.xml里面声明使用该Filter
<filter>
  <filter-name>Character Encoding</filter-name>
  <filter-class>com.webapps.commons.CharsetEncodingFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>Character Encoding</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
四、扩展
待续的是应用程序部分的国际化问题,和DB的国际化问题。
 
 
Struts国际化处理二
对于使用者来说,一个支持国际化的WEB程序具有下面几种形式
 
1. 根据用户浏览器自动设置显示的语言(无需用户干预)
2. 提供用户选择,用户根据自己的需要决定使用何种语言显示
3. 结合前两种.系统自动选择一种语言,但同时提供用户根据需要选择
 
使用Struts开发国际化程序是一件非常便利的事情,我们来看前两种怎么来实现
 
1. 这是最简单的方式,你不需要修改任何程序,只需要把资源文件按照各个语言翻译一遍并把这些文件按照国际化程序的要求命名好放置同一个目录即可. 例如 ApplicationResource_en_US.properties ApplicationResource_zh_TW.properties . 这种方式虽然自动的给用户设置好要显示的语言,但是有时候由于浏览器本身的问题,或者用户自己想看其他语种的时候就没有办法.
 
2. 这是比较常见的方式,由用户自己来选择所要显示的语言. 一般的情况是在首页或者登录页上增加语言的选项,用户选中其中一种登录后即以用户选择的语言进行显示,但是用户登录后必须把用户所选择的语言保存起来并让程序也就是<bean:message这些标签可以使用所选择的语言加载配置信息,因此在用户登录执行的Action类中加入如下代码
 
Locale locale = new Locale(request.getParameter("locale"));
//TODO:判断locale的有效性,无效的话不存入到sesssion中
req.getSession().setAttribute(Globals.LOCALE_KEY,locale);
 
好了,现在<bean:message/>这个标签库现在就可以根据你保存在session中的Locale对象来决定加载的是哪种语言, 通过看<bean:message/>标签库的源码我们就可以一目了然知道该标签库在加载资源前先从session或者该Locale对象, 如果为空则使用request.getLocale()这个值来加载对应语言的资源,因此这种做法实际上是实现了前面提到的第三种形式. 接下来就是翻译资源文件,有如第一步讲到的.
 
Struts框架在实现国际化应用程序的时候还是替我们想的很周到,因此你所需要做的就是翻译.
 
最后切记两点:
1. 页面的字符集必须是UTF-8,例如:
<%@ page language="java" contentType="text/html;charset=UTF-8" %>
2. 另外页面的所有的提示信息都应该在资源文件中定义

Global site tag (gtag.js) - Google Analytics