头像上传的插件似乎要用到的时候非常少,查了下网上提供的插件,有些还是使用GPL协议的,果断弃之。

最终选用了JCrop来实现(补充下JCrop提供多种编辑方式和样式,使用MIT License)。

MIT License:

   1: The MIT License
   2:  
   3: Copyright ©2008 Kelly Hallman and Deep Liquid Group
   4:  
   5: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
   6:  
   7: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
   8:  
   9:  
  10: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

头像上传的部分功能,只要是流程是这样:

1. 用户选择图片,上传至服务器后返回图片地址或其他参数返回给用户界面显示(上传的图片大小要做限制,如果图片大小符合要求但px即像素太大,也需要对图片进行一点比例的缩放处理,再返回)

2. 用户修改或者剪辑图片,根据需要剪辑图片大小和位置(可提供预览界面)

3. 保存图片(保存即将图片选取的坐标值传递至服务器,对图片做剪辑,并缩放至你显示给用户头像的大小)

前端效果一(选择图片):

image

效果一代码:

   1: <form action="<%=request.getContextPath() %>/uploadImg.do"
   2:                                         name="imgForm1" enctype="multipart/form-data" method="POST">
   3:                                         <input type="file" name="imgFile" onchange="submit();" />
   4:                                     </form>

前端效果二(服务器返回后生成图片提供编辑):

image

前端效果二代码:

   1: <script src="./scripts/jquery.min.js"></script>
   1:  
   2: <script src="./scripts/jquery.Jcrop.js">
   1: </script>
   2: <link rel="stylesheet" href="./css/jquery.Jcrop.css" type="text/css" />
   3: <%
   4: Object imgWO = request.getAttribute("imgWidth");
   5: int imgWidth = 0;
   6: if(null != imgWO) {
   7:     imgWidth = (Integer)imgWO;
   8: }
   9: Object imgHO = request.getAttribute("imgHeight");
  10: int imgHeight= 0;
  11: if(null != imgHO) {
  12:     imgHeight = (Integer)imgHO;
  13: }
  14: %>
  15: <script language="Javascript">
  16:  
  17:             // Remember to invoke within jQuery(window).load(...)
  18:             // If you don't, Jcrop may not initialize properly
  19:             jQuery(window).load(function(){
  20:  
  21:                 jQuery('#cropbox').Jcrop({
  22:                     setSelect: [ 100, 100, 200, 200 ],
  23:                     onChange: showCoords,
  24:                     onSelect: showPreview,
  25:                     aspectRatio: 1
  26:                 });
  27:             });
  28:  
  29:             // Our simple event handler, called from onChange and onSelect
  30:             // event handlers, as per the Jcrop invocation above
  31:             function showPreview(coords)
  32:             {
  33:                 var imgWidth = 300;
  34:                 var imgHeight = 300;
  35:                 var imgW = <%=imgWidth %>;
  36:                 var imgH = <%=imgHeight %>;
  37:                 if(imgW != null && imgW != 0) {
  38:                     imgWidth = imgW;
  39:                 }
  40:                 if(imgH != null && imgH != 0) {
  41:                     imgHeight = imgH;
  42:                 }
  43:             
  44:                 if (parseInt(coords.w) > 0)
  45:                 {
  46:                     var rx = 100 / coords.w;
  47:                     var ry = 100 / coords.h;
  48:  
  49:                     jQuery('#preview').css({
  50:                         width: Math.round(rx * imgWidth) + 'px',
  51:                         height: Math.round(ry * imgHeight) + 'px',
  52:                         marginLeft: '-' + Math.round(rx * coords.x) + 'px',
  53:                         marginTop: '-' + Math.round(ry * coords.y) + 'px'
  54:                     });
  55:                 }
  56:             }
  57:  
  58:             function showCoords(c)
  59:             {
  60:                 $('#x').val(c.x);
  61:                 $('#y').val(c.y);
  62:                 $('#x2').val(c.x2);
  63:                 $('#y2').val(c.y2);
  64:                 $('#w').val(c.w);
  65:                 $('#h').val(c.h);
  66:             };
  67:           
  68:           
  69:         

</script>

   2: <table width="800px">
   3:             <tr>
   4:                 <%
   1:  
   2:                 Object o = request.getAttribute("imgSrc");
   3:                 String imgSrc = "";
   4:                 if(null != o) {
   5:                     imgSrc = (String)o;
   6:                 }
   7:                 
   8:                 Object o1 = request.getAttribute("imgName");
   9:                 String imgName = "";
  10:                 if(null != o1) {
  11:                     imgName = (String)o1;
  12:                 }
  13:                 

%>

   5:                 <td width="400px">
   6:                 <div align="center">
   7:                 <form action="<%=request.getContextPath() %>/uploadImg.do"
   8:                     name="imgForm1" enctype="multipart/form-data" method="POST">
   9:                 <input type="file" name="imgFile" onchange="submit();" /></form>
  10:                 <img src="<%=imgSrc %>" id="cropbox" /></div>
  11:                 </td>
  12:                 <td width="400px">
  13:                 <form action="<%=request.getContextPath() %>/saveImg.do"
  14:                     name="imgForm" method="POST"><input type="hidden"
  15:                     name="imgName" id="imgName" value="<%=imgName %>" /> <label><input
  16:                     type="hidden" size="4" id="x" name="x" /></label> <label><input
  17:                     type="hidden" size="4" id="y" name="y" /></label> <label><input
  18:                     type="hidden" size="4" id="x2" name="x2" /></label> <label><input
  19:                     type="hidden" size="4" id="y2" name="y2" /></label> <label><input
  20:                     type="hidden" size="4" id="w" name="w" /></label> <label><input
  21:                     type="hidden" size="4" id="h" name="h" /></label>
  22:                 <div align="center">
  23:                 <div style="width:100px;height:100px;overflow:hidden;">
  24:                                             <img src="<%=imgSrc %>" id="preview" />
  25:                                         </div><br><br>
  26:                                         <input type="submit" value="保 存" name="submit"/>
  27:                                     </div>
  28:                                     </form> 
  29:                                 </td>
  30:                             </tr>
  31:                         </table>

前端效果三(保存后显示图片):

image

后端代码(上传图片+保存图片+缩放图片处理),由于使用SpringMVC,所以这里保存的图片的代码非常简单,你也可以使用smartupload或者commonupload等插件来实现或自己重写:

   1: //上传图片,并返回给浏览器
   2: public ModelAndView uploadImg(HttpServletRequest request,
   3:         HttpServletResponse response) throws Exception {
   4:     ModelAndView mv = new ModelAndView("profileImg.jsp");
   5:     String sourcePath = request.getRealPath("") + "/upload/";
   6:     String serverPath = request.getRealPath("") + "/upload/";
   7:     serverPath = serverPath.replace("\\", "/");
   8:  
   9:     MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
  10:     MultipartFile multipartFile = multipartRequest.getFile("imgFile");
  11:     File file = new File(sourcePath + multipartFile.getOriginalFilename());
  12:     multipartFile.transferTo(file);
  13:  
  14:     BufferedImage bi = ImageIO.read(file);
  15:     int w = bi.getWidth();
  16:     int h = bi.getHeight();
  17:     BufferedImage out = bi.getSubimage(0, 0, w, h);
  18:     out = resizeImage(out, BufferedImage.TYPE_INT_RGB, bi.getWidth(), bi.getHeight());
  19:     ImageIO.write(out, "jpg", file);
  20:     String imgSrc = "upload/" + multipartFile.getOriginalFilename();
  21:     mv.addObject("imgSrc", imgSrc);
  22:     mv.addObject("imgWidth", out.getWidth());
  23:     mv.addObject("imgHeight", out.getHeight());
  24:     mv.addObject("imgName", multipartFile.getOriginalFilename());
  25:     return mv;
  26: }
  27:  
  28: // 保存修剪后的头像
  29: public ModelAndView saveImg(HttpServletRequest request,
  30:         HttpServletResponse response) throws Exception {
  31:     ModelAndView mv = new ModelAndView("profileContent.jsp");
  32:     
  33:     String xStr = request.getParameter("x");
  34:     String yStr = request.getParameter("y");
  35:     String wStr = request.getParameter("w");
  36:     String hStr = request.getParameter("h");
  37:     int x = 0;
  38:     int y = 0;
  39:     int w = 300;
  40:     int h = 300;
  41:     if (null != xStr && !"".equals(xStr)) {
  42:         x = Integer.parseInt(xStr);
  43:     }
  44:  
  45:     if (null != yStr && !"".equals(yStr)) {
  46:         y = Integer.parseInt(yStr);
  47:     }
  48:     if (null != wStr && !"".equals(wStr)) {
  49:         w = Integer.parseInt(wStr);
  50:     } else {
  51:         w = 300;
  52:     }
  53:     if (null != hStr && !"".equals(hStr)) {
  54:         h = Integer.parseInt(hStr);
  55:     } else {
  56:         h = 300;
  57:     }
  58:  
  59:     String imgName = request.getParameter("imgName");
  60:       ServletContext context = getServletContext();
  61:       String  path = context.getRealPath("/") ;
  62:     String  path = request.getRealPath("/") ;
  63:     String sourcePath = path + "upload/";
  64:     String serverPath = path + "upload/" + imgName;
  65:     imgName = MD5.crypt(imgName);
  66:     String hashName = sourcePath + imgName + ".jpg";
  67:     BufferedImage bi = ImageIO.read(new File(serverPath));
  68:  
  69:     BufferedImage out = null;
  70:     if (w > 0 && h >0 && bi.getWidth() >= w && bi.getHeight() >= h) {
  71:         out = bi.getSubimage(x, y, w, h);
  72:     } else {
  73:         out = bi.getSubimage(0, 0, bi.getWidth(), bi.getHeight());
  74:     } 
  75:     
  76:     out = resizeImage(out, BufferedImage.TYPE_INT_RGB, 130, 130);
  77:     ImageIO.write(out, "jpg", new File(hashName));
  78:     response.setHeader("Pragma ", "No-cache ");
  79:     response.setHeader("Cache-Control ", "no-cache ");
  80:     response.setDateHeader("Expires ", 0);
  81:     request.getSession().setAttribute("imgSrc", "upload/" + imgName + ".jpg");
  82:  
  83:     return mv;
  84: }
  85:  
  86: //对图片大小进行缩放处理
  87: public BufferedImage resizeImage(BufferedImage originalImage,
  88:         int type, int width, int height) {
  89:     MathUtil mathUtil = new MathUtil();
  90:     Double rate = 0.0;
  91:     if (width < 300 && height < 300) {
  92:         BufferedImage resizedImage = new BufferedImage(width, height, type);
  93:         Graphics2D g = resizedImage.createGraphics();
  94:         g.drawImage(originalImage, 0, 0, width, height, null);
  95:         g.dispose();
  96:         return resizedImage;
  97:     } else {
  98:         rate = mathUtil.divide(new Double(height), new Double(300));
  99:         height = (int) mathUtil.divide(new Double(height), rate);
 100:         width = (int) mathUtil.divide(new Double(width), rate);
 101:     }
 102:     
 103:     BufferedImage resizedImage = new BufferedImage(width, height, type);
 104:     Graphics2D g = resizedImage.createGraphics();
 105:  
 106:     g.drawImage(originalImage, 0, 0, width, height, null);
 107:     g.dispose();
 108:  
 109:     return resizedImage;
 110: }

 

由于只是初稿,没有做逻辑和这种异常情况的判断,你可以根据你的需要自己增加。到这基本就完成了。

希望对你有帮助. 如有不足,敬请指出!

—-EOF—-

有一款文件比较软件Winmerge的文件夹比较功能比较少,只能比较当前目录下的文件数和文件差别。

但由于需要,查看两个类似的目录中,其中一个少了那些文件。所以就自己写了个脚本,来遍历。

代码如下,由于图省事 ‘\‘ 也没处理,就是列出其中一个文件夹少了哪些文件的功能。

   1: public static void compDir(String dir1, String dir2) {
   2:         File file1 = new File(dir1);
   3:         File file2 = new File(dir2);
   4:         Collection common = new ArrayList();
   5:         String[] tmp1 = null;
   6:         if(!file1.isDirectory()) {
   7:             return;
   8:         }
   9:         tmp1 = file1.list();
  10:         String[] tmp2 = null;
  11:         if(!file2.isDirectory()) {
  12:             return;
  13:         }
  14:         tmp2 = file2.list();
  15:  
  16:         if (tmp1.length > tmp2.length) {
  17:             //A目录比B目录文件数多的情况
  18:             for (int i = 0; i < tmp2.length; i++) {
  19:                 for (int j = 0; j < tmp1.length; j++) {
  20:                     if (tmp2[i].equals(tmp1[j])) {
  21:                         common.add(tmp2[i]);
  22:                     }
  23:                 }
  24:             }
  25:  
  26:             for (int i = 0; i < tmp1.length; i++) {
  27:                 if (!common.contains(tmp1[i])) {
  28:                     System.out.println(dir1 + "\\" + tmp1[i]);
  29:                 } else {
  30:                     File file = new File(dir1 + "\\" + tmp1[i]);
  31:                     if (file.isDirectory()) {
  32:                         compDir(dir1 +"\\"+ tmp1[i], dir2 +"\\"+ tmp1[i]);
  33:                     }
  34:                 }
  35:             }
  36:  
  37:         } else if (tmp1.length < tmp2.length) {
  38:             //A目录比B目录文件数少的情况
  39:             for (int i = 0; i < tmp1.length; i++) {
  40:                 for (int j = 0; j < tmp2.length; j++) {
  41:                     if (tmp1[i].equals(tmp2[j])) {
  42:                         common.add(tmp1[i]);
  43:                     }
  44:                 }
  45:             }
  46:  
  47:             for (int i = 0; i < tmp2.length; i++) {
  48:                 if (!common.contains(tmp2[i])) {
  49:                     System.out.println(dir2 + "\\" + tmp2[i]);
  50:                 } else {
  51:                     File file = new File(dir2 + "\\"+ tmp2[i]);
  52:                     if (file.isDirectory()) {
  53:                         compDir(dir1 +"\\"+ tmp2[i], dir2 +"\\"+ tmp2[i]);
  54:                     }
  55:                 }
  56:             }
  57:  
  58:         } else if (tmp1.length == tmp2.length) {
  59:             for(int i = 0; i< tmp1.length; i++) {
  60:                 common.add(tmp1[i]);
  61:                 compDir(dir1 +"\\"+ tmp1[i], dir2 +"\\"+ tmp1[i]);
  62:             }
  63:         }

如有不足,敬请见谅!

–EOF–

日志中显示
WARNING: No cluster interconnect has been specified. Depending on
the communication driver configured Oracle cluster traffic
may be directed to the public interface of this machine.
Oracle recommends that RAC clustered databases be configured
with a private interconnect for enhanced security and
performance.
查看网卡属性

rac2-> oifcfg getif
rac2->
可发现cluster_interconnects未配置,可通过oifcfg解决这个问题
rac2-> srvctl stop database -d devdb
rac2->
rac2->
rac2-> oifcfg setif -global eth0/192.168.1.0:public eth1/10.10.10.0:cluster_interconnect
rac2-> oifcfg getif
eth0 192.168.1.0 global public
eth1 10.10.10.0 global cluster_interconnect
[root@rac2 ~]# /u01/app/oracle/product/10.2.0/crs_1/bin/crsctl stop crs
Stopping resources.
Successfully stopped CRS resources
Stopping CSSD.
Shutting down CSS daemon.
Shutdown request successfully issued.
[root@rac2 ~]# /u01/app/oracle/product/10.2.0/crs_1/bin/crsctl start crs
Attempting to start CRS stack
The CRS stack will be started shortly
[root@rac2 ~]#

[root@rac2 ~]# /etc/init.d/init.crs start
Startup will be queued to init within 90 seconds.
[root@rac2 ~]#
[root@rac2 ~]# su – oracle
rac2-> crs_stat -t
Name Type Target State Host
————————————————————
ora.devdb.db application ONLINE ONLINE rac1
ora….b1.inst application ONLINE OFFLINE
ora….b2.inst application ONLINE ONLINE rac2
ora….SM1.asm application ONLINE ONLINE rac1
ora….C1.lsnr application ONLINE ONLINE rac1
ora.rac1.gsd application ONLINE UNKNOWN rac1
ora.rac1.ons application ONLINE UNKNOWN rac1
ora.rac1.vip application ONLINE ONLINE rac1
ora….SM2.asm application ONLINE ONLINE rac2
ora….C2.lsnr application ONLINE ONLINE rac2
ora.rac2.gsd application ONLINE ONLINE rac2
ora.rac2.ons application ONLINE ONLINE rac2
ora.rac2.vip application ONLINE ONLINE rac2
rac2-> oifcfg getif
eth0 192.168.1.0 global public
eth1 10.10.10.0 global cluster_interconnect

        写这篇文章仅仅是这几天遇到和想到的一些东西,就写出来,也没做多大整理。没有大纲和标线,思路很随意。

        都说人人生而平等,人与人之间不管你贫穷还是富有。即使是这样,我们的出生却很大程度上决定了我们今后的一部分生活。因而产生了了两种不同的概念,精神层面的平等和物质层面的平等。即在原始意义上我们每个人还是平等的,不管你来自刚果金还是来自美利坚。但在物质层面上,如果你坐拥几个亿,且不算多。但与非洲、印度、中国的贫穷地区的人们相比,同在一个场合出现,或许两者的平等的天平很快会失去平衡。这种高下不是我们刻意或故意捏造的,而是由日渐发展的社会和日益变化的人心综合的结果。所以我就觉得,有些稍富的群体产生一定的优越感完全是不能避免而不由自己的。即使是内心善良、美好的人,在当今社会在神奇的国度,也会慢慢被改变一些。

        前两天张江这边一个清洗大楼外墙的清洁工从楼上掉下来了,不知道是否从危险中回复回来。有时候去小饭馆吃饭,饭馆里都是民工朋友即所谓的体力劳动者。一身的灰和粗犷的模样很容易一眼就认出他们。住处是在一家酒店旁的居民楼里,经过酒店的时候会路过开在弄堂口的足浴店,劣质的沙发上坐着几个穿着暴露表情冷漠浓妆艳抹的姑娘。同样是底层工作者,只是稍显高级的脑力劳动者,码农。在偌大的上海滩横竖都占不了2平方,在人流中不起眼的一员。每天在经历着和大多数人相同的生活,起床-上班-下班-回家。有时候确实很让人觉得自己的卑微渺小,只是在想,如果农民工朋友自己愿意接受更好的教育,而现实情况也允许的话。是不是他的人生他的生活也会产生不一样变化呢?答案是显而易见的。但在社会属性中,不同的工种不同的人群都扮演着自己的角色。某种层面上社会需要这些,即使在美利坚,体力劳动者也存在相当的部分(他们的薪资却相当不错,甚至还高于坐在办公室的白领)。即使这样,如果,假如有那么个机会恐怕没有几个体力劳动者不想对自己的现状有所改观,但现实却几乎没有这样的机会。因而很多人将自己的期望和希望寄托在自己的孩子身上,希望孩子能走和自己不一样的道路能有更好的发展,因而教育这件神圣的事被寄托和负担了太多的压力和负担。孩子们在这条路上走的远走的近都大大的受到了影响。就个人觉得,这样的情况可能带来改变也可能不会。教育在我们每个人的生命都起着不可脱离的作用。说到教育恐怕真的不是几句话就能说明白,暂且跳过这段。说到妓女会让人联想起《Oliver Twist》中的场景,丑陋龌龊肮脏所有负面的词汇和场景都似乎和这种职业能联想到一块。但如果设身处地的想,远离家乡,文化程度低,没有糊口的生计,只身一人,在大城市,不让农村或来在贫穷地域的家人担心和供养。要在这里,做点什么呢?试问,又有几个职位能满足所有外来务工者呢。即使在通常人眼中,出卖肉体与灵魂,这样的职业却也有它自己存在的群体。可能有些人没有想那么多,就是想赚点钱,可能有些人都不觉得和灵魂有关;也可能有些人本身就在受着来自自己内心的煎熬与痛苦,又有几人有切身的体会。底层工作者,因而也是弱势群体。有些没有医保,社保,公积金,有些甚至都没有最基本的安全保障。有些可能还要受到侮辱。这在人与人平等的本身其实是矛盾的。众多坐办公室的白领,虽体面也在该阶层中不得不承认自己底层工作者的本质。至少,我自己就是这么认为的。

        不知不觉没有逻辑框架的随笔,总是那么难以下笔。庆幸的是我竟然能写到这里了。那么我们是否该做点什么呢,不能改变改善别人是否能改善自己的生活态度或者对待其他人群的态度呢?更加友善,更加宽容去接受这些原本可能会发生在我们自己身上的事情,和正在承受这些的人们。珍惜眼前与活在当下当然非常值得提倡,但同时如果我们与此同时能朝着计划的理想和目标慢慢靠近。哪怕不能扑入火焰,朝火焰靠近的温暖也会让我们觉得幸福和愉悦。

        先写到这吧,其实在大师的技术博客上写些有的没的,还是挺不好意思的哈哈。祝看到这篇文章的朋友多思考多感受,让生活更美好!

1、/etc/hosts文件内需正确指明本地回路解析地址(localhost)
2、PUBLIC网卡必须配置getway address
3、保证各节点时钟同步

战士的宿命就是战死沙场,微博上留下这么一条,花去很长时间在思考这样的问题

兵者,永远是沙场的主人。弥漫的硝烟下,穿上战甲,跨上战马,奋战前线,驰骋沙场,挥洒着血与汗水,领着千军万马,随时准备好与敌人拼死搏斗,一怒而安天下之民。几近疯狂的状态,无所畏缩,无所顾忌,认清目标后,坚定脚步,任何艰难、痛苦都可以忍受,任何打击都不能销毁战士的意志。战士,只能浴血沙场,眼里只有千军万马。

他不会停留,更不会堕落,他无法停下自己的脚步,当找不到自己的沙场时,他会迷茫,他会不安,他会不知所措。

他不会放弃,没有灰心与绝望,即使失败,也会在无数鲜血染红的废墟上摸爬滚打,重振旗鼓,重新回到战争中去,举着长剑,挥舞着手臂,他要的是王冠,纵然战死沙场,也是一身傲骨。

试验环境:

OS:Linux 4

Tuxedo:10.3

鉴于Tuxedo卓越的运行效率,并可持续为用户提供服务,本文针对Tuxedo高可用性方面进行分析,力求以实际试验结果来说明Tuxedo各个部件的高可用性实现方式。由于个人水平有限,有结果不一致之处以官方说明为准。

涉及Tuxedo组件:

Tuxedo /WS

Tuxedo MP

Tuxedo多域

 

高可用性简介

 

系统的可用性是指系统处于正常可用状态的时间所占的百分比,系统可用性下降通常由两个因素导致:系统失败率和系统恢复时间。有以下两个方法可以衡量系统的可用性:

平均无故障时间(MTBF):是指系统在正常运行状态的平均时间

平均恢复时间(MTTR):是指在系统失败之后,需要多长时间来恢复系统

因此,系统的可用性可定义为:可用性= MTBF /(MTBF + MTTR)

那么提高系统的可用性就可从两方面出发:提高系统的可靠性,并降低系统失败恢复时间

 

环境简介

 

本试验所使用的架构示意图如下:

image

从客户端出发,首先连接DOM1域,DOM1域为MP(多机)模式,DOM1域主要用来为用户提供连接池,并从DOM2、DOM3导入同名服务,转发客户端请求,DOM2、DOM3提供实际服务

 

各组件高可用性分析

 

客户端:

Tuxedo客户端通过设置WSNADDR并以特定的符号分割,可以实现在客户端进行tpinit()时的failover以及负载均衡,设置方法为:

export WSNADDR=(//192.168.1.50:3333"|"//192.168.1.51:3333),//192.168.1.51:3333,//192.168.1.50:3333

当WSNADDR以“,”分割时,客户端会首先判断第一个地址是否可用,若不可用就按顺序尝试后面的地址;当WSNADDR以“|”分割,客户端会随机使用所分割的地址进行连接建立。当前配置中,正常情况下可以在192.168.1.50;3333以及192.168.1.51:3333之间进行负载均衡,当某个地址无法建立连接时,即进行“,”后面地址尝试。示意图如下:

image

这种方式所实现的高可用性,在于判断是否可完成tpinit()操作,即与WSL建立连接过程,若WSL进程正常,且可正常进行连接建立,则不会发生failover过程。

多机模式:

多机(MP)模式下,可实现多机中各节点之间的负载均衡和容错功能,客户端可任何一个节点建立连接,如果该服务器上没有该客户端所要调用的service,Tuxedo可以自动把请求发送到其它的有该service的机器上处理,并把结果返回到客户端,请求通过BRIDGE进程在这些服务器之间进行传递。当然,这些对客户端是透明的。不仅如此,如果设置了负载均衡(LDBAL=Y),那么Tuxedo将根据它们的负载情况报,将请求发送到负载较小的服务器上。而且还提供软件级别的Cluster功能,如果其中某-台或几台(当然不能是全部)服务器出现故障了,那么正常的机器仍然能够继续运行,如果它们之间的网络连接断了,BRIDGE进程会自动进行重试,并且在这些服务器之间可以配置多个网络连接通路,当其中的一个出现故障时,会自动采用别的连接通路。

image

多网关进程

可在Tuxedo中配置多个网关组,设置域网关进程连接策略为ON_STARTUP或INCOMINGONLY,即可实现failover机制,当某个网关进程失败,均可实现透明地将请求转交给其他可用网关进程处理。示意图如下:

image

图中,当地一个网关进程失败之后,系统会选择其他可用的网关进程去进行连接,并转发客户端请求。

多域failover

若多个域同时提供同名服务,那么可设置网关进程连接策略为“ON_STARTUP”或”INCOMINGONLY“,示意图如下所示:

image

如上图所示,DOM2、DOM3均想DOM1提供了”a“的服务,若DOM2失败,DOM1中的客户端请求会自动转发至DOM3进行处理,保证系统持续运行。同时该方式还可实现多域之间的负载均衡。

多实例

通过ubb配置文件中,配置*SERVER段中对应server的MIN/MAX参数,设定每个进程的实例启动数量,若其中一个server失败,客户端请求可转发至其他可用server进行处理。同时server还可以设置可重启特性,可保证在server实例失败之后,最快将失败的重新实例启动。

案例分析

本案例为当前应用较广的高可用性方案,相关参数配置如下:

DOM1:

  • ubb配置

*RESOURCES
#IPCKEY         <Replace with a valid IPC Key>

#Example:
IPCKEY          123456

DOMAINID        dom1
MASTER          simple1,simple2
MAXACCESSERS    100
MAXSERVERS      50
MAXSERVICES     100
MODEL           MP
LDBAL           Y
OPTIONS         LAN,MIGRATE

*MACHINES
DEFAULT:
                APPDIR="/app/tuxedo/dom1"
                TUXCONFIG="/app/tuxedo/dom1/tuxconfig"
                TUXDIR="/app/tuxedo/tuxedo10gR3"
                MAXWSCLIENTS=10
myvm1           LMID=simple1
                APPDIR="/app/tuxedo/dom1"
                TUXCONFIG="/app/tuxedo/dom1/tuxconfig"
                TUXDIR="/app/tuxedo/tuxedo10gR3"
                MAXWSCLIENTS=10
myvm2           LMID=simple2
                UID=503
                GID=503

#Example:
#beatux         LMID=simple

*GROUPS
GROUP1
        LMID=simple1    GRPNO=1 OPENINFO=NONE
GROUP2  LMID=simple2    GRPNO=2 OPENINFO=NONE

DMGRP1  LMID=simple1    GRPNO=3 OPENINFO=NONE
GWGRP1  LMID=simple1    GRPNO=5 OPENINFO=NONE
GWGRP2  LMID=simple1    GRPNO=6 OPENINFO=NONE
GWGRP3  LMID=simple2    GRPNO=7 OPENINFO=NONE
GWGRP4  LMID=simple2    GRPNO=8 OPENINFO=NONE

*SERVERS
DEFAULT:
                CLOPT="-A"
WSL             SRVGRP=GROUP1   SRVID=2
                CLOPT="-A — -n //192.168.1.50:3333 -m 2 -M 5 -x 10"

#simpserv       SRVGRP=GROUP1 SRVID=1
WSL             SRVGRP=GROUP2   SRVID=4
                CLOPT="-A — -n //192.168.1.51:3333 -m 2 -M 5 -x 10"

simpserv        SRVGRP=GROUP1   SRVID=15
DMADM           SRVGRP=DMGRP1   SRVID=5
GWADM           SRVGRP=GWGRP1   SRVID=6
GWTDOMAIN       SRVGRP=GWGRP1   SRVID=7
GWADM           SRVGRP=GWGRP2   SRVID=8
GWTDOMAIN       SRVGRP=GWGRP2   SRVID=9
GWADM           SRVGRP=GWGRP3   SRVID=10
GWTDOMAIN       SRVGRP=GWGRP3   SRVID=11
GWADM           SRVGRP=GWGRP4   SRVID=12
GWTDOMAIN       SRVGRP=GWGRP4   SRVID=13
*NETWORK
simple1 NADDR="//192.168.1.50:7000"
        NLSADDR="//192.168.1.50:7001"
simple2 NADDR="//192.168.1.51:7000"
        NLSADDR="//192.168.1.51:7001"
BRIDGE="/dev/tcp"

*SERVICES

域配置:

*DM_LOCAL
"LDOM1" TYPE=TDOMAIN    GWGRP="GWGRP1" DOMAINID="LDOM1" CONNECTION_POLICY=ON_STARTUP
"LDOM2" TYPE=TDOMAIN    GWGRP="GWGRP2" DOMAINID="LDOM2" CONNECTION_POLICY=ON_STARTUP
"LDOM3" TYPE=TDOMAIN    GWGRP="GWGRP3" DOMAINID="LDOM3" CONNECTION_POLICY=ON_STARTUP
"LDOM4" TYPE=TDOMAIN    GWGRP="GWGRP4" DOMAINID="LDOM4" CONNECTION_POLICY=ON_STARTUP
*DM_REMOTE
"RDOM1" TYPE=TDOMAIN DOMAINID="RDOM1"
"RDOM2" TYPE=TDOMAIN DOMAINID="RDOM2"
"RDOM3" TYPE=TDOMAIN DOMAINID="RDOM3"
"RDOM4" TYPE=TDOMAIN DOMAINID="RDOM4"

*DM_TDOMAIN
"LDOM1" NWADDR="//192.168.1.50:5555"
"LDOM2" NWADDR="//192.168.1.50:6666"
"LDOM3" NWADDR="//192.168.1.51:5555"
"LDOM4" NWADDR="//192.168.1.51:6666"
"RDOM1" NWADDR="//192.168.1.50:7777"
"RDOM2" NWADDR="//192.168.1.50:8888"
"RDOM3" NWADDR="//192.168.1.51:7777"
"RDOM4" NWADDR="//192.168.1.51:8888"
*DM_EXPORT
*DM_IMPORT
TOUPPER RDOM=RDOM1,RDOM2,RDOM3,RDOM4
TOUPPER RDOM=RDOM2,RDOM3,RDOM4,RDOM1
TOUPPER RDOM=RDOM3,RDOM4,RDOM1,RDOM2
TOUPPER RDOM=RDOM4,RDOM1,RDOM2,RDOM3

DOM2

  • ubb配置:

*RESOURCES
#IPCKEY         <Replace with a valid IPC Key>

#Example:
IPCKEY          123453

DOMAINID        dom2
MASTER          dom2
MAXACCESSERS    100
MAXSERVERS      50
MAXSERVICES     100
MODEL           SHM
LDBAL           N

*MACHINES
DEFAULT:
                APPDIR="/app/tuxedo/dom2"
                TUXCONFIG="/app/tuxedo/dom2/tuxconfig"
                TUXDIR="/app/tuxedo/tuxedo10gR3"
#Example:
#               APPDIR="/home/me/simpapp"
#               TUXCONFIG="/home/me/simpapp/tuxconfig"
#               TUXDIR="/usr/tuxedo"

myvm2           LMID=dom2

#Example:
#beatux         LMID=simple

*GROUPS
GROUP1
        LMID=dom2       GRPNO=1 OPENINFO=NONE
DMGRP   LMID=dom2       GRPNO=2 OPENINFO=NONE
GWGRP1  LMID=dom2       GRPNO=3 OPENINFO=NONE
GWGRP2  LMID=dom2       GRPNO=4 OPENINFO=NONE
GWGRP3  LMID=dom2       GRPNO=5 OPENINFO=NONE

*SERVERS
DEFAULT:
                CLOPT="-A"

simpserv        SRVGRP=GROUP1 SRVID=1 MIN=2     MAX=2
DMADM           SRVGRP=DMGRP   SRVID=5
GWADM           SRVGRP=GWGRP1   SRVID=8
GWTDOMAIN       SRVGRP=GWGRP1   SRVID=7
GWADM           SRVGRP=GWGRP2   SRVID=10
GWTDOMAIN       SRVGRP=GWGRP2   SRVID=9
GWADM           SRVGRP=GWGRP3   SRVID=12
GWTDOMAIN       SRVGRP=GWGRP3   SRVID=11

*SERVICES
TOUPPER

  • 域配置:

*DM_LOCAL
"RDOM3" TYPE=TDOMAIN GWGRP="GWGRP1" DOMAINID="RDOM3"
"RDOM4" TYPE=TDOMAIN GWGRP="GWGRP2" DOMAINID="RDOM4"
"RDOM6" TYPE=TDOMAIN GWGRP="GWGRP3" DOMAINID="RDOM6"
*DM_REMOTE
"LDOM1" TYPE=TDOMAIN DOMAINID="LDOM1"
"LDOM2" TYPE=TDOMAIN DOMAINID="LDOM2"
"LDOM3" TYPE=TDOMAIN DOMAINID="LDOM3"
"LDOM4" TYPE=TDOMAIN DOMAINID="LDOM4"
*DM_TDOMAIN
"LDOM1" NWADDR="//192.168.1.50:5555"
"LDOM2" NWADDR="//192.168.1.50:6666"
"RDOM3" NWADDR="//192.168.1.51:7777"
"RDOM4" NWADDR="//192.168.1.51:8888"
"LDOM3" NWADDR="//192.168.1.51:5555"
"LDOM4" NWADDR="//192.168.1.51:6666"
"*DM_EXPORT
*DM_IMPORT

DOM3:

  • ubb配置:

*RESOURCES
#IPCKEY         <Replace with a valid IPC Key>

#Example:
IPCKEY          123451

DOMAINID        dom3
MASTER          dom3
MAXACCESSERS    100
MAXSERVERS      50
MAXSERVICES     100
MODEL           SHM
LDBAL           N

*MACHINES
DEFAULT:
                APPDIR="/app/tuxedo/dom3"
                TUXCONFIG="/app/tuxedo/dom3/tuxconfig"
                TUXDIR="/app/tuxedo/tuxedo10gR3"
#Example:
#               APPDIR="/home/me/simpapp"
#               TUXCONFIG="/home/me/simpapp/tuxconfig"
#               TUXDIR="/usr/tuxedo"

myvm1           LMID=dom3

#Example:
#beatux         LMID=simple

*GROUPS
GROUP1
        LMID=dom3       GRPNO=1 OPENINFO=NONE
DMGRP   LMID=dom3       GRPNO=2 OPENINFO=NONE
GWGRP1  LMID=dom3       GRPNO=3 OPENINFO=NONE
GWGRP2  LMID=dom3       GRPNO=4 OPENINFO=NONE
GWGRP3  LMID=dom3       GRPNO=5 OPENINFO=NONE

*SERVERS
DEFAULT:
                CLOPT="-A"

simpserv        SRVGRP=GROUP1 SRVID=1 MIN=2     MAX=2
DMADM           SRVGRP=DMGRP   SRVID=5
GWADM           SRVGRP=GWGRP1   SRVID=8
GWTDOMAIN       SRVGRP=GWGRP1   SRVID=7
GWADM           SRVGRP=GWGRP2   SRVID=10
GWTDOMAIN       SRVGRP=GWGRP2   SRVID=9
GWADM           SRVGRP=GWGRP3   SRVID=11
GWTDOMAIN       SRVGRP=GWGRP3   SRVID=12

*SERVICES
TOUPPER

  • 域配置:

*DM_LOCAL
"RDOM1" TYPE=TDOMAIN GWGRP="GWGRP1" DOMAINID="RDOM1"
"RDOM2" TYPE=TDOMAIN GWGRP="GWGRP2" DOMAINID="RDOM2"
*DM_REMOTE
"LDOM1" TYPE=TDOMAIN DOMAINID="LDOM1"
"LDOM2" TYPE=TDOMAIN DOMAINID="LDOM2"
"LDOM3" TYPE=TDOMAIN DOMAINID="LDOM3"
"LDOM4" TYPE=TDOMAIN DOMAINID="LDOM4"
*DM_TDOMAIN
"LDOM1" NWADDR="//192.168.1.50:5555"
"LDOM2" NWADDR="//192.168.1.50:6666"
"LDOM3" NWADDR="//192.168.1.51:5555"
"LDOM4" NWADDR="//192.168.1.51:6666"
"RDOM1" NWADDR="//192.168.1.50:7777"
"RDOM2" NWADDR="//192.168.1.50:8888"
"RDOM5" NWADDR="//192.168.1.50:9999"
*DM_EXPORT
*DM_IMPORT
TOUPPER

该模式可在如下情况下持续工作:

客户端与DOM1中任意一个节点网络失败

  • DOM1中单个节点WSL失败
  • DOM1所有节点中最多3个网关进程失败
  • DOM2、DOM3任意三个网关进程失败
  • DOM1中任意一个节点失败
  • DOM2、DOM3其中一个域失败

其中需要注意的是,在故障发生时刻,由于公告板中未来得及清理注册信息,可能会导致某些请求调用失败。

Cross-Site-Scripting也称跨站脚本攻击,缩写通常为XSS.

或者先到这里补充下知识:http://en.wikipedia.org/wiki/Cross-site_scripting

由于工作需要最近在研究一些常用的攻击方式和漏洞,用以预防和修复.如果你还没有听过说这些,可能你需要先阅读下以下的内容以帮助你快速进入状态。

XSS主要可分为三种,Reflected、Persistent、DOM等三种.通常危害较大,也Web应用中存在很多潜在的可以运用XSS的方法。以下是摘自网络的一些描述和解释,希望你能耐心看完并思考、最好还能动手就更好了。

1.Cross-Site Scripting: Reflected

Abstract:

Sending unvalidated data to a web browser can result in the browser executing malicious code.

Explanation:

Cross-site scripting (XSS) vulnerabilities occur when:

1. Data enters a web application through an untrusted source. In the case of Reflected XSS, the untrusted source is typically a web request, while in the case of Persisted (also known as Stored) XSS it is typically a database or other back-end datastore.

2. The data is included in dynamic content that is sent to a web user without being validated for malicious code.The malicious content sent to the web browser often takes the form of a segment of JavaScript, but may also include HTML,Flash or any other type of code that the browser may execute. The variety of attacks based on XSS is almost limitless, but they commonly include transmitting private data like cookies or other session information to the attacker, redirecting the victim to web content controlled by the attacker, or performing other malicious operations on the user’s machine under the guise of the vulnerable site.

示例代码:

<% String id = request.getParameter(“id”); %>

<%=id %>

Reflected XSS 受害的方式:

黑客或者恶意的攻击者,可以通过发送包含恶意脚本的url连接邮件。使用一些社会工程的方式让受害者相信这些链接并点击。既而,脚本会在受害者的浏览器中运行并进行恶意的动作。可能是跳转到挂木马的网站、可能是盗取你的重要cookie的信息并默默发送到攻击者指定的服务器、可能是毁坏受害者的电脑……

2.Cross-Site Scripting: Persistent

Abstract:

Sending unvalidated data to a web browser can result in the browser executing malicious code.

Explanation:

Cross-site scripting (XSS) vulnerabilities occur when:

1. Data enters a web application through an untrusted source. In the case of Persistent (also known as Stored) XSS, the untrusted source is typically a database or other back-end datastore, while in the case of Reflected XSS it is typically a web request.

2. The data is included in dynamic content that is sent to a web user without being validated for malicious code. The malicious content sent to the web browser often takes the form of a segment of JavaScript, but may also include HTML,Flash or any other type of code that the browser may execute. The variety of attacks based on XSS is almost limitless, but they commonly include transmitting private data like cookies or other session information to the attacker, redirecting the victim to web content controlled by the attacker, or performing other malicious operations on the user’s machine under the guise of the vulnerable site.

示例代码:

<%

while(rs.next()) {

String str = rs.getString(“content”);

%>

<%=str %>

<% } %>

Persistent XSS 受害的方式:

恶意脚本等被提交进入受害者方式的服务器数据库中,当受害者访问数据库中相应的数据并在浏览器中显示时,从数据库中取出的内容(恶意脚本)被浏览器解析成脚本而被执行,在受害者的电脑上执行。既而,脚本会在受害者的浏览器中运行并进行恶意的动作。可能是跳转到挂木马的网站、可能是盗取你的重要cookie的信息并默默发送到攻击者指定的服务器、可能是毁坏受害者的电脑……

3. Cross-Site Scripting: DOM

Abstract:
Sending unvalidated data to a web browseer can result in the browser executing malicious code.
Explanation:
Cross-site scripting (XSS) vulnerabilities occur when:
1. Data enters a web application through an untrusted source. In the case of DOM-based XSS, data is read from a URL parameter or other value within the browser and written back into the page with client-side code. In the case of Reflected XSS, the untrusted source is typically a web request, while in the case of Persisted (also known as Stored) XSS it is typically a database or other back-end datastore.
2. The data is included in dynamic content that is sent to a web user without being validated for malicious code. In the case of
DOM Based XSS, malicious code gets executed as part of DOM (Document Object Model) creation, whenever the victim’s browser parses the HTML page.The malicious content sent to the web browser often takes the form of a segment of JavaScript, but may also include HTML,Flash or any other type of code that the browser may execute. The variety of attacks based on XSS is almost limitless, but they
commonly include transmitting private data like cookies or other session information to the attacker, redirecting the victim to web content controlled by the attacker, or performing other malicious operations on the user’s machine under the guise of the vulnerable site.

示例代码:

<SCRIPT>

var pos=document.URL.indexOf(“eid=”)+4;

document.write(document.URL.substring(pos,document.URL.length));

</SCRIPT>

DOM XSS 受害的方式:

服务器端的代码中直接使用DOM对象,将从request请求中获取的内容动态的写到页面中。但是如果request请求的参数是攻击者恶意构造的脚本,那么恶意脚本也会被浏览器解析成脚本被执行。既而,脚本会在受害者的浏览器中运行并进行恶意的动作。可能是跳转到挂木马的网站、可能是盗取你的重要cookie的信息并默默发送到攻击者指定的服务器、可能是毁坏受害者的电脑……

XSS常用解决办法

1.Contextual output encoding/escaping of string input,Safely validating untrusted HTML input:

对输入和输出的内容进行验证、转译或者重新编码等。(另外Struts 1.x和Struts 2的标签都会对input和output进行encoding和escaping,所以Struts是个不错的选择).

2.Disabling scripts:在浏览器中使JavaScript失效(通过修改浏览器设置,但是如果在禁用掉javascript也是不太好的方式)

3.Cookie security:让登录的session的cookie与指定的ip绑定

4.其他

XSS推荐相关链接:

Knowledge1 https://www.owasp.org/index.php/XSS

Knowledge2:http://en.wikipedia.org/wiki/Cross-site_scripting#Contextual_output_encoding.2Fescaping_of_string_input

Knowledge3http://www.iseclab.org/papers/xss_prevention.pdf

Solution1:Decode the input or output string(use tld Tag Library Descriptor)or Add a filter

http://www.ibm.com/developerworks/tivoli/library/s-csscript/

Solution2:http://today.java.net/article/2005/09/19/handling-java-web-application-input-part-2

Character entity references in HTML

http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML

Struts Tag Explain1:

1.Bean tag

http://struts.apache.org/1.x/struts-taglib/tlddoc/bean/tld-summary.html

http://struts.apache.org/1.x/struts-taglib/tlddoc/bean/parameter.html

If no request parameter with the specified name can be located, and no default value is specified, a request time exception will be thrown.

2.Logic tag

http://struts.apache.org/1.x/struts-taglib/tlddoc/logic/tld-summary.html

http://struts.apache.org/1.x/struts-taglib/tlddoc/logic/present.html

But considering the network limitation, we can also download the tld files and put them into our project . so that the struts tag can work

如有不足敬请谅解,另外如果你有其他角度和想法欢迎交流 ^_^

——-EOF——

由于工作需要接手到使用Struts 1.x的项目,且需要使用struts的一些属性,故在自己本地搭建了下环境来练习,希望能对你有帮助。

1.搭建环境,下载struts-1.3.10-all.zip, 包括jar包、源码、例子、文档

1.1创建一个Web Project

1.2导入jar包(一般放入WEB-INF/lib目录)

1.3建立一个配置文件:struts-config.xml(一般放在WEB-INF下)EN0f09623aexample- struts-config.xml

1.4在web.xml中注册struts控制器-ActionServlet(注意文件配置位置和预先加载控制器)EN0f09624aexample- web.xml

2.建立ActionForm

2.1建立一个类,继承ActionFormEN0f096259example- LoginForm.java

2.2注册,修改配置文件struts-config.xml

3.建立Action

3.1建立一个类,继承Action,重写execute()方法EN0f096269example- LoginAction.java

struts的Action相当于MVC模型中的Controller.

4.页面访问

EN0f096278EN0f096288EN0f096298

在浏览器中输入链接地址进入页面访问

Tips(小技巧):

由于之前开发都用的是MyEclipse,第一次用J2EE 版Eclipse 还是遇到了一些问题。

1.Tomcat增加后,启动,发现在浏览器中无法通过http://localhost:8080/访问

解决办法:

双击sever后,在如下界面中,选择“Use Tomcat installation (takes control of Tomcat installtion)”.默认是选的第一项。

Image

2.导入jar包,以前是用右键点击项目名,build path中进去后,增加jar包和library,但是发现启动Tomcat之后无法找到相应的类,而业务层的java文件中能够找到增加的jar包

解决办法:

将jar包直接增加到WEB-INF/lib目录下,问题即可解决。同时最好把之前通过build path增加的jar包去掉

—-EOF—-

以前习惯在现场解决问题,所以就可以随心所欲,想看啥就看啥,没有一定的套路,这样有时可以快速的定位问题,但也有可能错过重要的信息。当远程处理问题时,首先要做到收集完整的信息,所以IBM提供了许多MustGather,另外一个很重要的工具就是Trace。

Trace其实就是WAS的日志,就像Log4J,你可以为每个模块分配一个单独的名字,然后可以区分日志的级别,这样在Trace配置页面,我们就可以通过名字和级别,控制是否输出某个模块的信息。

//定义Trace对象,类似Log4J中的Logger。SSL就是所谓的模块名,而后面的类名则是另一个名字
private static final TraceComponent tc = Tr.register(SSLSocketFactory.class, "SSL", "com.ibm.ws.ssl.resources.ssl");

//普通输出
if (tc.isDebugEnabled()) Tr.debug(tc, "Getting javax.net.ssl.* SSL System properties.");

//进入方法的Trace
if (tc.isEntryEnabled()) Tr.entry(tc, "SSLSocketFactory(1)");

//退出方法的Trace
if (tc.isEntryEnabled()) Tr.exit(tc, "SSLSocketFactory(1)");

对应这些代码,就会看到一些Trace输出信息:

[12/1/11 18:10:57:888 GMT+08:00] 00000017 SSLSocketFact 3   Getting javax.net.ssl.* SSL System properties.

[12/1/11 18:10:57:881 GMT+08:00] 00000017 SSLSocketFact >  SSLSocketFactory(1) Entry

[12/1/11 18:10:57:883 GMT+08:00] 00000017 SSLSocketFact <  SSLSocketFactory(1) Exit

有了这么详细的Trace,结合代码,基本上可以重现故障发生时的上下文和参数,找到对应的错误就变得易如反掌了。

,