222011

public class Test {

public  static  void  encode(byte[]  in,  byte[]  out,  int  password)
{
int  len  =  in.length;

int  seed  =  password  ^  0×3810860;
for  (int  i  =  0  ;  i  <  len;  ++i)  {
/**
*因为JVM中涉及byte、short、char类型的运算操作首先会把这些值转换成int类型,
* 然后对int类型的值进行运算,所以需要把运算结果强制转换成byte类型
*/
byte  a  =  (byte)(  (  in[i]  ^  seed  )  >>>  5  );//把异或后的值存放在a的低3位
byte  b  =  (byte)(  (  (  ((int)in[i])  <<  20 )  ^  seed  )  >>>  (20-3)  );//把异或后的值存放在b的高5位
a  &=  0×7;//0×7:0000 0111;将a中未存储有效数的位清零
b  &=  0xf8;//0xf8:1111 1000;将b中未存储有效数的位清零
out[i]  =  (byte)(a  |  b);
seed  =  ((seed  ^  out[i])  *  7321  +  out[i]);
}
}

public  static  void  decode(byte[]  in,  byte[]  out,  int  password)
{
int  len  =  in.length;

int  seed  =  password  ^  0×3810860;
for  (int  i  =  0  ;  i  <  len;  ++i)  {
//  fill  the  code  here
}
}
public  static  void  main(String  []  args)  throws  Exception
{
int  password  =  0x808d0625;
byte[]  buf1  =  {-36,  -108,  -73,  95,  56,  80,  -103,  -49,  59,  -52,  -30,  70,  -93,  88,  110,  -128,  88,  -42,  1,  114,  -117,  -67,  -84,  55,  24,  -107,  -97,  -51,  60,  -117,  113,  38,  110,  -103,  -70,  100,  54,  -126,  };
byte[]  buf2  =  new  byte[buf1.length];
decode(buf1,  buf2,  password);
System.out.println(new  String(buf2,  “GBK”));
}
} Continue reading »

JAVA中使用LDAP进行用户认证

Posted by 冰河 at 11:18 1 Response » 20,000 Views
302011

转篇文章自用

LDAP的英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP,这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。现在LDAP技术不仅发展得很快而且也是激动人心的。在企业范围内实现LDAP可以让运行在几乎所有计算机平台上的所有的应用程序从 LDAP目录中获取信息。LDAP目录中可以存储各种类型的数据:电子邮件地址、邮件路由信息、人力资源数据、公用密匙、联系人列表,等等。通过把 LDAP目录作为系统集成中的一个重要环节,可以简化员工在企业内部查询信息的步骤,甚至连主要的数据源都可以放在任何地方。
Continue reading »

十二 082010

编者按:原文作者Jenkov就是那位丹麦的资深Java开发人员,从事软件开发已有十多年。除了常有读者咨询他《如何成为一位专家级的开发人员?》之外,“怎么才能成为一名Java自由开发人员?”也是他收件箱中另一个常收到的问题。

自由职业者的工作是什么?

不知你是否知道,我是一名自由职业的Java开发人员,这意味着我从事咨询工作。我从2000年开始从事这份工作,它占了我职业生涯的大部分时间。我多数是在为大公司、软件公司、银行和运输公司等客户工作。

我每次参与的项目会持续3到12个月。在那段时间内,我出现在客户的办公室里,就像他们自己的员工一样。一些项目是构建新的应用程序,其他的则是为现有的应用程序添加一些功能。

我参与开发的许多应用程序都是内部应用,由客户的员工本身或者客户的客户使用。这些应用程序中,很多网络应用程序是利用Java servlets和JSP等构建的,或者是使用独立的服务端服务。客户还从未要求过我去开发任何图形界面程序。

以我的经验,自由职业者很少受雇开发Facebook那样的产品。公司倾向于用正式员工进行此类产品的开发。

公司为什么雇佣自由开发人员?

当大公司要在一定期限内开发一个项目,而他们又没有足够人手的时候,他们就不时地在外面雇佣顾问。这些公司在一定时期内雇佣顾问,然后等到项目结束时或者或任务不那么紧迫的时候就把他们炒掉。

如此一来,大公司就可以很容易并快速地雇佣和解雇开发人员,而又不必顾虑雇员会在合同到期时有所不满。

通常当新项目需要额外人手的时候,公司会再次雇佣同一个顾问,因此客户对顾问的个性和技能已有所了解。再就是客户不必就流程、开发工具和硬件设置等问题上再次对顾问进行培训。

怎样成为一名自由职业者?

正常来说自由职业者要通过咨询机构来找活干。咨询机构会和客户保持联系。

大客户不愿意直接和无数的自由职业者联系,也不愿意和他们每一个人单独谈薪水等问题。当额外需要人手的时候,客户只需和咨询机构谈即可。并且,如果你违约,提前解除了合同,咨询机构还能快速帮客户找到其他开发员。

所以,找到当地雇佣自由职业者的咨询机构,和他们保持联系。如此一来,你已进入他们的人才库。

做自由职业者有什么要求?

在接受你之前,大多数的咨询机构要求你至少有5年的开发经验。我很幸运,在干过1年网络开发和1年Java咨询工作后,我就进入了自由职业这一行,成 为一 家咨询机构的正式员工。只用两年,这之所以成为可能是因为2000年的互联网泡沫。当时每个人都在雇佣开发人员,因此市场不像今天这么不景气。

自由职业者的薪水如何?

在丹麦,顾问的薪水的一般都是正式员工的1.5到2倍。薪水的高低和技术水平以及教育背景有很大关系。在一些特殊的领域薪水可能更高,在一些大众化的领域(比如PHP),薪水要低些。

为什么要从事自由职业?

我喜欢从事自由职业这一行,因为恰如其名,相比正式员工,我自由了很多。

首先,我不用在同一个地方年复一年的工作。并不是在所有的公司工作都那么有激情。作为一名自由职业者,我可以到处走走,甚至是在一段时间后再回到一个公司工作。

其次,我可以选择性工作。这意味着我可以更好地控制我的职业生涯方向。当然并非总可以控制方向,但有时候的确可以。至少当一个项目与你的方向相差甚远时,你可以拒绝。

第三,高薪水允许我抽出一部分时间去旅游,或者开发我自己的小软件项目,又或者写写文章,比如这篇文章。 Continue reading »

282010

java 代码

1private final String getClientAddress(HttpServletRequest request) {
2
3 String address = request.getHeader(X-Forwarded-For);
4
5 if (address != null && StringUtil.isIPAddress(address)) {
6
7 return address;
8
9 }

10
11 return request.getRemoteAddr();
12
13}

14

另外原因主要是Squid的使用:

参见:www.blogjava.net/Alpha/archive/2006/07/12/57764.aspx

在很多应用下都可能有需要将用户的真实IP记录下来,这时就要获得用户的真实IP地址,在JSP里,获取客户端的IP地址的方法是:request.getRemoteAddr(), 这种方法在大部分情况下都是有效的。但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了。

这段时间在做IP统计的程序设计,由于服务器作了集群,使用了反向代理软件,将http://192.168.1.110:2046/的URL反向代理 为http://www.xxx.com/的URL时,用request.getRemoteAddr()方 法获取的IP地址是:127.0.0.1 或 192.168.1.110, 而并不是客户端的真实IP。这是什么原因呢?

这是反向代理的原因。经过代理以后,由于在客户端和服务之间增加了中间层,因此服务器无法直接拿到客户端的IP,服务器端应用也无法直接通过转发请求的地 址返回给客户端。但是在转发请求的HTTP头信息中,增加了X-FORWARDED-FOR信息。用以跟踪原有的客户端IP地址和原来客户端请求的服务器 地址。当我们访问http://www.xxx.com/index.jsp/时, 其实并不是我们浏览器真正访问到了服务器上的index.jsp文件,而是先由代理服务器去访问http://192.168.1.110:2046/index.jsp, 代理服务器再将访问到的结果返回给我们的浏览器,因为是代理服务器去访问index.jsp的,所以index.jsp中通过request.getRemoteAddr()的 方法获取的IP实际上是代理服务器的地址,并不是客户端的IP地址。

异常代码:

org.hibernate.exception.GenericJDBCException: could not insert: [com.huama.equma.entity.DicPackage]
java.sql.DataTruncation: Data truncation
java.sql.SQLException: 将截断字符串或二进制数据org.hibernate.exception.GenericJDBCException: could not insert: [com.yp.Person]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:103)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:91)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2272)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.yp.db.PersistenceService.save(PersistenceService.java:191)
at com.yp.action.PersonAction.personAdd(PersonAction.java:216)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:274)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:194)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:419)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:224)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1194)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.yp.db.Filter.doFilter(PersistenceFilter.java:46)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.yp.util.Filter.doFilter(EncodingFilter.java:45)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.DataTruncation: Data truncation
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:378)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2778)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2214)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:597)
at net.sourceforge.jtds.jdbc.JtdsStatement.processResults(JtdsStatement.java:465)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQL(JtdsStatement.java:427)
at net.sourceforge.jtds.jdbc.JtdsPreparedStatement.executeUpdate(JtdsPreparedStatement.java:397)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2252)
… 45 more

出错分析:在jdbc插入数据时,当数据库表中某列设置的长度小于要插入的字符的实际长度时就会抛出此异常。

如:数据表中某列char [4],长度为4,插入:”string”时,字符”string”长度超过4,抛出异常。据超过了字段的限制导致截断

解决方法:在.hbm配置文件中把String长度设置大一些,默认是255

282010
  1. package com.geedao.util;
  2. /**
  3. * @author 卢向 东 lxdhdgss@gmail.com 检验输入
  4. */
  5. public class Regex {
  6. /**
  7. * 检查 email输入是否正确
  8. * 正确的书写格 式为 username@domain
  9. * @param value
  10. * @return
  11. */
  12. public boolean checkEmail(String value, int length) {
  13. return value.matches(“\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*”)&&value.length()<=length;
  14. }
  15. /**
  16. * 检查电话输入 是否正确
  17. * 正确格 式 012-87654321、0123-87654321、0123-7654321
  18. * @param value
  19. * @return
  20. */
  21. public boolean checkTel(String value) {
  22. return value.matches(“\d{4}-\d{8}|\d{4}-\d{7}|\d(3)-\d(8)”);
  23. }
  24. /**
  25. * 检查手机输入 是否正确
  26. *
  27. * @param value
  28. * @return
  29. */
  30. public boolean checkMobile(String value) {
  31. return value.matches(“^[1][3,5]+\d{9}”);
  32. }
  33. /**
  34. * 检查中文名输 入是否正确
  35. *
  36. * @param value
  37. * @return
  38. */
  39. public boolean checkChineseName(String value, int length) {
  40. return value.matches(“^[u4e00-u9fa5]+$”)&&value.length()<=length;
  41. }
  42. /**
  43. * 检查HTML 中首尾空行或空格
  44. * @param value
  45. * @return
  46. */
  47. public boolean checkBlank(String value){
  48. return value.matches(“^\s*|\s*$”);
  49. }
  50. /**
  51. * 检查字符串是 否含有HTML标签
  52. * @param value
  53. * @return
  54. */
  55. public boolean checkHtmlTag(String value){
  56. return value.matches(“<(\S*?)[^>]*>.*?</\1>|<.*? />”);
  57. }
  58. /**
  59. * 检查URL是 否合法
  60. * @param value
  61. * @return
  62. */
  63. public boolean checkURL(String value){
  64. return value.matches(“[a-zA-z]+://[^\s]*”);
  65. }
  66. /**
  67. * 检查IP是否 合法
  68. * @param value
  69. * @return
  70. */
  71. public boolean checkIP(String value){
  72. return value.matches(“\d{1,3}+\.\d{1,3}+\.\d{1,3}+\.\d{1,3}”);
  73. }
  74. /**
  75. * 检查ID是否 合法,开头必须是大小写字母,其他位可以有大小写字符、数字、下划线
  76. * @param value
  77. * @return
  78. */
  79. public boolean checkID(String value){
  80. return value.matches(“[a-zA-Z][a-zA-Z0-9_]{4,15}$”);
  81. }
  82. /**
  83. * 检查QQ是否 合法,必须是数字,且首位不能为0,最长15位
  84. * @param value
  85. * @return
  86. */
  87. public boolean checkQQ(String value){
  88. return value.matches(“[1-9][0-9]{4,13}”);
  89. }
  90. /**
  91. * 检查邮编是否 合法
  92. * @param value
  93. * @return
  94. */
  95. public boolean checkPostCode(String value){
  96. return value.matches(“[1-9]\d{5}(?!\d)”);
  97. }
  98. /**
  99. * 检查身份证是 否合法,15位或18位
  100. * @param value
  101. * @return
  102. */
  103. public boolean checkIDCard(String value){
  104. return value.matches(“\d{15}|\d{18}”);
  105. }
  106. /**
  107. * 检查输入是否 超出规定长度
  108. *
  109. * @param length
  110. * @param value
  111. * @return
  112. */
  113. public boolean checkLength(String value, int length) {
  114. return ((value == null || “”.equals(value.trim())) ? 0 : value.length()) <= length;
  115. }
  116. /**
  117. * 检查是否为空 字符串,空:true,不空:false
  118. *
  119. * @param value
  120. * @return
  121. */
  122. public boolean checkNull(String value) {
  123. return value == null || “”.equals(value.trim());
  124. }
  125. }
242010

最近在做一个推荐系统的项目,原来是设计前台一个表单对应后台一个form和action。无奈前台表单太多,只能把表单合并处理(在vo里都是对应同一个类,只是处理不同的逻辑)。这样就在前台表单里加了2个参数type和method。type用来区分form里的validate,然后利用method使用DispatchAction类。

采用 DispathAction
* 如果覆写DispathAction中的execute方法,必须显示的用super调用execute方法
* parameter参数值不能是execute或perform
* 了解<action>标签中的parameter的含义
* 了解DispathAction中的unspecified方法的含义

DispatchAction 的定义:
public abstract class DispatchAction extends Action
这是一个抽象的Action,它会根据request 中的parameter来执行相应的方法。通个这个Action类可以将不同的Action集中到一个Action文件中来。

Struts-config.xml:

<action path=”/saveSubscription” type=”org.apache.struts.actions.DispatchAction” name=”subscriptionForm” scope=”request” input=”/subscription.jsp” parameter=”method”/>

在Action中要有相应的方法:

Public class demoAction extends DispatchAction{

public ActionForward delete(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

public ActionForward insert(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

public ActionForward update(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception

}

你就可以通过这样的方法来访问你的程序:

http://localhost:8080/myapp/saveSubscription.do?method=update

如果parameter中参数为空,则执行Action中unspecified方法
DispatchAction就是在struts-config中用parameter参数 配置一个表单字段名,这个字段的值就是最终替代execute被调用的方法. 例如parameter=”method”而request.getParameter(“method”)=”save”,其中”save”就是 MethodName。struts的请求将根据parameter被分发到”save”或者”edit”或者什么。但是有一点,save()或者 edit()等方法的声明和execute必须一模一样。

DispatchAction的父类是 Action ,它的作用就在于将多个功能相似的业务逻辑放在同一个 Action 中实现,各个业务逻辑通过传入不同的参数来决定执行哪个操作方法

通常在 Action 中我们都是通过 execute 方法来处理业务逻辑及页面转向,一个 Action 只能完成一种业务逻辑处理 , 当然我们也可以在页面插入一个隐藏的变量,然后在 Action execute 方法中通过判断这个隐藏变量的值来决定调用哪个方法,也可以达到同 一个 Action 来处理多种业务逻辑

DispatchAction 是如何实现的?

比如对一个用户对象来说,存在增加,删除,修改的操作,首先创建一 个继承 DispatchAction UserAction 类,

然后将 addUser,delUser,updateUser 这些方法写在这个类里面,代码如下:

package com.why.struts.action;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.actions.DispatchAction;

import com.why.Constant;

import com.why.struts.form.AddUserForm;

import com.why.struts.form.LoginForm;

public class UserAction extends DispatchAction

{

public ActionForward addUser (ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 增加用户业务的逻辑

return mapping.findForward(Constant. FORWARD_ADD );

}

public ActionForward delUser(ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 删除用户业务的逻辑

return mapping.findForward(Constant. FORWARD_SUCCESS );

}

public ActionForward updateUser(ActionMapping mapping,ActionForm form,

HttpServletRequest request,HttpServletResponse response) throws Exception

{

// 更新用户业务的逻辑

return mapping.findForward(Constant. FORWARD_SUCCESS );

}

}

如何实现这些不同方法的调用呢 ? 那就是要在 struts-config.xml 文件中更改 action-mapping 的配置,如下:

< action-mappings >

< action

attribute = “addUserForm”

input = “/addUser.jsp”

name = “addUserForm”

parameter=”method”

path = “/addUser”

scope = “request”

type=”com.why.struts.action.UserAction” >

</ action >

< action

attribute = “delUserForm”

input = “/delUser.jsp”

name = “delUserForm”

parameter=”method”

path = “/delUser”

scope = “request”

type=”com.why.struts.action.UserAction” />

< action

attribute = “updateUserForm”

input = “/updateUser.jsp”

name = “updateUserForm”

parameter=”method”

path = “/updateUser”

scope = “request”

type=”com.why.struts.action.UserAction” />

</ action-mappings >

可以看到每个 <action  /> 中都增加了 parameter=” “ 项,这个值可以随便命名,如上面命名为 metho d ,用来接收页面传来的参数

如下为页面的提交, 注意:对应 <action  /> 中的 parameter , 对应 UserAction 类中的方法名

AddUser.jsp

<html:link href=”addUser.do?method=addUser“>Add User</html:link>

DelUser.jsp

<html:link href=”delUser.do?method=delUser“>Add User</html:link>

UpdateUser.jsp

<html:link href=”updateUser.do?method=updateUser“>Add User</html:link>

说实话写Java程序总是大手大脚的,很少在乎内存。以前最多就是用system.gc()命令,今天看一个开源的程序,无意中发现作者在写Java时也用了很多查看内存的方法,这里转载一篇相关的文章。

最近在网上看到一些人讨论到java.lang.Runtime类中的 freeMemory(),totalMemory(),maxMemory()这几个方法的一些问题,很多人感到很疑惑,为什么,在java程序刚刚启 动起来的时候freeMemory()这个方法返回的只有一两兆字节,而随着java程序往前运行,创建了不少的对象,freeMemory()这个方法 的返回有时候不但没有减少,反而会增加。这些人对freeMemory()这个方法的意义应该有一些误解,他们认为这个方法返回的是操作系统的剩余可用内 存,其实根本就不是这样的。这三个方法反映的都是java这个进程的内存情况,跟操作系统的内存根本没有关系。下面结合 totalMemory(),maxMemory()一起来解释。
maxMemory()这个方法返回的是java虚拟机(这个进程)能构从操作系统那里挖到的最大的内存,以字节为单位,如果在运行java程序的时 候,没有添加-Xmx参数,那么就是64兆,也就是说maxMemory()返回的大约是64*1024*1024字节,这是java虚拟机默认情况下能 从操作系统那里挖到的最大的内存。如果添加了-Xmx参数,将以这个参数后面的值为准,例如java -cp ClassPath -Xmx512m ClassName,那么最大内存就是512*1024*0124字节。
totalMemory()这个方法返回的是java虚拟机现在已经从操作系统那里挖过来的内存大小,也就是java虚拟机这个进程当时所占用的所有 内存。如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操作系统那里挖的,基本上是用多少挖多少,直 挖到maxMemory()为止,所以totalMemory()是慢慢增大的。如果用了-Xms参数,程序在启动的时候就会无条件的从操作系统中挖 -Xms后面定义的内存数,然后在这些内存用的差不多的时候,再去挖。
freeMemory()是什么呢,刚才讲到如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操 作系统那里挖的,基本上是用多少挖多少,但是java虚拟机100%的情况下是会稍微多挖一点的,这些挖过来而又没有用上的内存,实际上就是 freeMemory(),所以freeMemory()的值一般情况下都是很小的,但是如果你在运行java程序的时候使用了-Xms,这个时候因为程 序在启动的时候就会无条件的从操作系统中挖-Xms后面定义的内存数,这个时候,挖过来的内存可能大部分没用上,所以这个时候freeMemory()可 能会有些大。
把下面的源代码编译以后,在class文件所在的目录里面,分别用java -cp . Untitled1 和java -cp . -Xms80m -Xmx80m Untitled1 运行,看看结果如何,有助于理解上面的阐述。
public class Untitled1 {
    public Untitled1() {
    }

    public static void main(String[] args) {
        System.out.println(Runtime.getRuntime().freeMemory());
        System.out.println(Runtime.getRuntime().totalMemory());
        System.out.println(Runtime.getRuntime().maxMemory());
        long t = System.currentTimeMillis();
        try {
            Thread.sleep(30000);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        String[] aaa = new String[2000000];
        System.out.println(Runtime.getRuntime().freeMemory());
        System.out.println(Runtime.getRuntime().totalMemory());
        System.out.println(Runtime.getRuntime().maxMemory());
        try {
            Thread.sleep(30000);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
        for (int i = 0; i < 2000000; i++) {
            aaa[i] = new String("aaa");
        }
        System.out.println(Runtime.getRuntime().freeMemory());
        System.out.println(Runtime.getRuntime().totalMemory());
        System.out.println(Runtime.getRuntime().maxMemory());
        try {
            Thread.sleep(30000);
        } catch (Exception ee) {
            ee.printStackTrace();
        }
    }

}

原文链接:http://blog.sina.com.cn/s/blog_473d30e1010007dm.html

完整的代码如下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* JAVA操作SSL协议,通过Socket访问Https的程序代码例子。
*
*
*/
public class ReadHttpsURL {
// 默认的HTTPS 端口      visit
static final int HTTPS_PORT = 443;
public static void main(String argv[]) throws Exception {
// 受访主机
String host = “www.google.com”;
// 受访的页面
String url = “/adsense/?sourceid=aso&subid=ZH_CN-ET-AS-ADSBY6&medium=link&hl=zh_CN”;
// 自定义的管理器
X509TrustManager xtm = new Java2000TrustManager();
TrustManager mytm[] = { xtm };
// 得到上下文
SSLContext ctx = SSLContext.getInstance(“SSL”);
// 初始化
ctx.init(null, mytm, null);
// 获得工厂
SSLSocketFactory factory = ctx.getSocketFactory();
// 从工厂获得Socket连接
Socket socket = factory.createSocket(host, HTTPS_PORT);
// 剩下的就和普通的Socket操作一样了
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out.write(“GET ” + url + ” HTTP/1.0

“);
out.flush();
System.out.println(“start   work!”);
String line;
StringBuffer sb = new StringBuffer();
while ((line = in.readLine()) != null) {
sb.append(line + ”
“);
}
out.close();
in.close();
System.out.println(sb.toString());
}
}
/**
* 自定义的认证管理类。
*
*
*/
class Java2000TrustManager implements X509TrustManager {
Java2000TrustManager() {
// 这里可以进行证书的初始化操作
}
// 检查客户端的可信任状态
public void checkClientTrusted(X509Certificate chain[], String authType) throws CertificateException {
System.out.println(“检查客户端的可信任状态…”);
}
// 检查服务器的可信任状态
public void checkServerTrusted(X509Certificate chain[], String authType) throws CertificateException {
System.out.println(“检查服务器的可信任状态”);
}
// 返回接受的发行商数组
public X509Certificate[] getAcceptedIssuers() {
System.out.println(“获取接受的发行商数组…”);
return null;
}
}

在web应用交互过程中,有很多场景需要保证通信数据的安全;在前面也有好多篇文章介绍了在Web Service调用过程中用WS-Security来保证接口交互过程的安全性,值得注意的是,该种方式基于的传输协议仍然是Http,采用这种方式可扩 展性和数据交互效率比较高;另外一种实现方式就是用Https,他是在协议层对Http的再次封装,加入了SSL/TLS,采用该协议进行通信的数据全部 都会被加密,由于目前Web开发编程中对此都有了一定程度的封装,所以采用Https对外提供服务,除了证书以外,对编程能力的要求并不高,相对于前者门 槛较低,但是由于对双方通信的所有数据都进行加密,而且交互过程中还有多次握手等,所以效率较低;以下就介绍下在Java中访问Https链接时会出现的 一些问题;

在Java中要访问Https链接时,会用到一个关键类HttpsURLConnection;参见如下实现代码:

// 创建URL对象
URL myURL = new URL(“https://www.sun.com”);

// 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
HttpsURLConnection httpsConn = (HttpsURLConnection) myURL
.openConnection();

// 取得该连接的输入流,以读取响应内容
InputStreamReader insr = new InputStreamReader(httpsConn
.getInputStream());

// 读取服务器的响应内容并显示
int respInt = insr.read();
while (respInt != -1) {
System.out.print((char) respInt);
respInt = insr.read();
}

在取得connection的时候和正常浏览器访问一样,仍然会验证服务端的证书是否被信任(权威机构发行或者被权威机构签名);如果服务端证书不被信任,则默认的实现就会有问题,一般来说,用SunJSSE会抛如下异常信息:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

上面提到SunJSSE,JSSE(Java Secure Socket Extension)是实现Internet安全通信的一系列包的集合。它是一个SSL和TLS的纯Java实现,可以透明地提供数据加密、服务器认证、 信息完整性等功能,可以使我们像使用普通的套接字一样使用JSSE建立的安全套接字。JSSE是一个开放的标准,不只是Sun公司才能实现一个 SunJSSE,事实上其他公司有自己实现的JSSE,然后通过JCA就可以在JVM中使用。
关于JSSE的详细信息参考官网Reference:http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html
以及Java Security Guide:http://java.sun.com/j2se/1.5.0/docs/guide/security/

在深入了解JSSE之前,需要了解一个有关Java安全的概念:客户端的TrustStore文件。客户端的TrustStore文件中保存着被客 户端所信任的服务器的证书信息。客户端在进行SSL连接时,JSSE将根据这个文件中的证书决定是否信任服务器端的证书。在SunJSSE中,有一个信任 管理器类负责决定是否信任远端的证书,这个类有如下的处理规则:
1、若系统属性javax.net.sll.trustStore指定了TrustStore文件,那么信任管理器就去jre安装路径下的lib/security/目录中寻找并使用这个文件来检查证书。
2、若该系统属性没有指定TrustStore文件,它就会去jre安装路径下寻找默认的TrustStore文件,这个文件的相对路径为:lib/security/jssecacerts
3、若jssecacerts不存在,但是cacerts存在(它随J2SDK一起发行,含有数量有限的可信任的基本证书),那么这个默认的TrustStore文件就是lib/security/cacerts

那遇到这种情况,怎么处理呢?有以下两种方案:
1、按照以上信任管理器的规则,将服务端的公钥导入到jssecacerts,或者是在系统属性中设置要加载的trustStore文件的路径;证书导入可以用如下命令:keytool -import -file src_cer_file –keystore dest_cer_store;至于证书可以通过浏览器导出获得;
2、实现自己的证书信任管理器类,比如MyX509TrustManager,该类必须实现X509TrustManager接口中的三个method;然后在HttpsURLConnection中加载自定义的类,可以参见如下两个代码片段,其一为自定义证书信任管理器,其二为connect时的代码:

package test;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {

/*
* The default X509TrustManager returned by SunX509.  We’ll delegate
* decisions to it, and fall back to the logic in this class if the
* default X509TrustManager doesn’t trust it.
*/
X509TrustManager sunJSSEX509TrustManager;

MyX509TrustManager() throws Exception {
// create a “default” JSSE X509TrustManager.

KeyStore ks = KeyStore.getInstance(“JKS”);
ks.load(new FileInputStream(“trustedCerts”),
“passphrase”.toCharArray());

TrustManagerFactory tmf =
TrustManagerFactory.getInstance(“SunX509″, “SunJSSE”);

tmf.init(ks);

TrustManager tms [] = tmf.getTrustManagers();

/*
* Iterate over the returned trustmanagers, look
* for an instance of X509TrustManager.  If found,
* use that as our “default” trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
sunJSSEX509TrustManager = (X509TrustManager) tms[i];
return;
}
}

/*
* Find some other way to initialize, or else we have to fail the
* constructor.
*/
throw new Exception(“Couldn’t initialize”);
}

/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
sunJSSEX509TrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}

/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}

/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return sunJSSEX509TrustManager.getAcceptedIssuers();
}
}

// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance(“SSL”, “SunJSSE”);

sslContext.init(null, tm, new java.security.SecureRandom());

// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();

// 创建URL对象
URL myURL = new URL(“https://ebanks.gdb.com.cn/sperbank/perbankLogin.jsp”);

// 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
HttpsURLConnection httpsConn = (HttpsURLConnection) myURL.openConnection();
httpsConn.setSSLSocketFactory(ssf);

// 取得该连接的输入流,以读取响应内容
InputStreamReader insr = new InputStreamReader(httpsConn.getInputStream());

// 读取服务器的响应内容并显示
int respInt = insr.read();
while (respInt != -1) {
System.out.print((char) respInt);
respInt = insr.read();
}

对于以上两种实现方式,各有各的优点,第一种方式不会破坏JSSE的安全性,但是要手工导入证书,如果服务器很多,那每台服务器的JRE都必须做相同的操作;第二种方式灵活性更高,但是要小心实现,否则可能会留下安全隐患;

© 2009 - 2024 冰河的博客