想必不少人听说过javaagent,但是很少人听说Instrumentation,其实Instrumentation就是javaagent的实现机制,说到Instrumentation,就必须想了解java的attach机制,那就先说下attach的实现。
大家进行jstack的时候,是不是经常看到两个线程Signal Dispatcher和 Attach Listener线程,可能不知道是干嘛的吧,这两个线程是实现attach的关键所在,其中前者是在jvm启动的时候就会创建的,后者只有接收过attach请求的时候vm才会创建,顾名思义,Signal Dispatcher是分发信号的, Attach Listener 是处理attach请求的,那么两者有什么关系呢,当我们执行attach方法的时候,会向目标vm发出一个SIGQUIT 的信号,目标vm收到这个信号之后就会创建Attach Listener线程了,当然jvm保证了不会多创建。
1 path = findSocketFile(pid);
2 if (path == null) {
3 File f = new File(tmpdir, ".attach_pid" + pid);
4 createAttachFile(f.getPath());
5 try {
6 sendQuitTo(pid);
7
8 // give the target VM time to start the attach mechanism
9 int i = 0;
10 long delay = 200;
11 int retries = (int)(attachTimeout() / delay);
12 do {
13 try {
14 Thread.sleep(delay);
15 } catch (InterruptedException x) { }
16 path = findSocketFile(pid);
17 i++;
18 } while (i <= retries && path == null);
19 if (path == null) {
20 throw new AttachNotSupportedException(
21 "Unable to open socket file: target process not responding " +
22 "or HotSpot VM not loaded");
23 }
24 } finally {
25 f.delete();
26 }
27 }
Attach机制说得简单点就是提供A进程可以连上B进程(当然是java进程),创建socket进行通信,A通过发命令给B,B然后对命令进行截取从自己的vm中获取信息发回给客户端vm,但是并不是随便发指令都会处理的,那么attach Listener接收哪些命令呢,如下所示
static AttachOperationFunctionInfo funcs[] = {
{ "agentProperties", get_agent_properties },
{ "datadump", data_dump },
{ "dumpheap", dump_heap },
{ "load", JvmtiExport::load_agent_library },
{ "properties", get_system_properties },
{ "threaddump", thread_dump },
{ "inspectheap", heap_inspection },
{ "setflag", set_flag },
{ "printflag", print_flag },
{ "jcmd", jcmd },
{ NULL, NULL }
};
Instrumentation的实现其实主要使用了load这个指令,它用来实现让target vm动态加载agentlib,Instrumentation的实现在一个名为libinstrument.dylib的动态lib库,linux下是libinstrument.so,它是基于jvmti接口实现的,因此在对其进行load的时候会创建一个agent实例,并往jvmti环境注册一些回调方法,比如监听类文件加载的事件,vm初始化完成事件等,执行Agent_OnAttach,这里会创建一个Instrumentation实例并返回给用户供大家扩展Instrumentation,比如增加一些transform。并会执行Instrumentation实例的loadClassAndCallAgentmain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的agentmain方法,当vm初始化完毕之后,会调用loadClassAndCallPremain方法,该方法主要执行agent的MF文件里定义的 Agent-Class类的pre main方法。在类进行加载的时候会调用Instrumentation的transform方法,可以看看参数里有个byte数组,这个数组其实就是正在加载的class字节码,所以如果要字节码增强在这里就可以入手啦,甚至可以实现偷天换日.
posted @
2013-04-12 22:38 你假笨 阅读(2193) |
评论 (0) |
编辑 收藏
最近在忙一个项目,使用的是Flex+Spring+Hibernate,期间碰到一个问题,有必要在此记录一下,也方便有相似问题的来者参考下
问题描述:有一个用户表和一个用户详情表,这两个表是一个一对一的单向关联关系,即在用户表中一个外键引用用户详情表,我在UserInfo的映射文件中使用的是many-to-one,设置了unique="true"表示一对一关系,设置了cascade="save-update"表示的是在保存useInfo对象的时候会自动保存与之关联的userDetails临时对象,即我希望的是先执行一个在用户详情表中的插入语句然后再执行一个在用户表中的插入语句,userInfo对象是从flex端传过来的,当然也设置了userDetails属性的值,在userInfo的dao文件中save方法是这样的
public IvUserInfo save(IvUserInfo transientInstance) {
log.debug("saving IvUserInfo instance");
try {
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
return transientInstance;
}
后面发现执行的sql语句只有一条插入语句,就是在用户表中的一个插入,由于外键的关联作用,是用户表的这条插入也无法执行,这就是问题所在了。
问题解决:这个问题我也没有具体研究Hibernate的源码,我先写了个测试类,发现仅仅在java中执行操作的话是可以正确执行两条插入语句的,但是通过flex传过来就有问题了,那说明是flex端传参数过来的问题,于是我试着修改UserInfo的save方法:
public IvUserInfo save(IvUserInfo transientInstance) {
log.debug("saving IvUserInfo instance");
try {
IvUserDetails ud=new IvUserDetails();
ud.setQq(transientInstance.getIvUserDetails().getQq());
transientInstance.setIvUserDetails(ud);
getHibernateTemplate().save(transientInstance);
log.debug("save successful");
} catch (RuntimeException re) {
log.error("save failed", re);
throw re;
}
return transientInstance;
}
这样一来问题解决了,顺利执行了两条插入语句。
如果朋友知道具体原因的话希望给我留言了,同时也希望该记录能帮助碰到此类问题的朋友。
posted @
2010-06-22 11:20 你假笨 阅读(1564) |
评论 (0) |
编辑 收藏
欢迎光临笔者博客
http://www.lovestblog.cn
最近两天本人在为本博实现rss发布和订阅,本来是想在前端实现xml的生成和修改,因为用as3的E4X操作xml比较方便,但是后面发现不能为元素设置CDATA值,于是只好作罢,便只能依靠后台的java来实现此功能了,当然操作xml的话,我首先想到了dom4j,dom4j操作xml还是比较方便的,即可以轻松实现我们的CDATA设置,也可以为我们任意位置插入元素提供了实现,对于在指定位置新增节点开始我有点蒙了,后面通过网上搜索资源加之自己的一些理解,而实现了此功能,下面展示了部分代码供今后参考吧:
-
public static int createXMLFile(String filename,List list){
/** *//** 返回操作结果, 0表失败, 1表成功 */
int returnValue = 0;
Document document = DocumentHelper.createDocument();
Element rssElement = document.addElement("rss");
rssElement.addAttribute("version", "2.0");
Element channelElement = rssElement.addElement("channel");
Element titleElement = channelElement.addElement("title");
titleElement.setText("你假笨(nijiaben)心情技术博客");
Element linkElement = channelElement.addElement("link");
linkElement.setText("http://www.lovestblog.cn");
Element descriptionElement = channelElement.addElement("description");
descriptionElement.setText("专注于Java,Flex技术开发研究");
Element languageElement = channelElement.addElement("language");
languageElement.setText("zh-cn");
Element lastBuildDateElement = channelElement.addElement("lastBuildDate");
lastBuildDateElement.setText(new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(((ArticleInfo)(list.get(0))).getCreateTime()));
for(int i=list.size()-1;i>0;i--){
ArticleInfo ainfo=(ArticleInfo)(list.get(i));
Element itemElement = channelElement.addElement("item");
Element title1Element = itemElement.addElement("title");
title1Element.setText(ainfo.getTitle());
Element description1Element = itemElement.addElement("description");
int maxLen=5000;
if(ainfo.getRssContent().length()<5000){
maxLen=ainfo.getRssContent().length();
}
description1Element.addCDATA(ainfo.getRssContent().substring(0, maxLen));
Element pubDate=itemElement.addElement("pubDate");
pubDate.setText(new java.text.SimpleDateFormat("yyyy-mm-dd hh:mm:ss",Locale.CHINA).format(ainfo.getCreateTime()));
Element link1Element=itemElement.addElement("link");
link1Element.setText("http://www.lovestblog.cn");
}
try{
/** *//** 将document中的内容写入文件中 */
XMLWriter writer = new XMLWriter(new FileOutputStream(path+filename));
writer.write(document);
writer.close();
/** *//** 执行成功,需返回1 */
returnValue = 1;
}catch(Exception ex){
ex.printStackTrace();
}
return returnValue;
}
posted @
2010-04-01 12:14 你假笨 阅读(3078) |
评论 (1) |
编辑 收藏
本文最新发布于http://www.lovestblog.cn,欢迎转载该文,但请注明文章出处,谢谢合作。
mysql的from从句用来指定参与查询的表,当然也可以是生成的中间表,在表前我们有时需要指定数据库,这主要是用在我们需要访问当前数据库之外的数据库中的表的情况,在这中情况下我们采用"."操作符来进行,如userdb.user,其实userdb为数据库名,user为表名,这是对mysql数据库而言的,对于DB2和Oracle就不是通过指定数据库名了,而是指定sql用户了,这就是说不同sql用户可以建立相同名字的表,但是同一个sql用户只能建立唯一名字的表。这就是它们在这表规范上面的区别。对于列规范,mysql可以在需要查询的列则可以采用如下形式进行访问:“数据库名.表名.列名”。对于多个表的规范,也就是涉及查询多个表的情况下,执行的过程是采用笛卡尔积的形式进行的。也就是说生成的中间表的列数为两个表中列数的总和,而行的总数等于一个表中的行的数量与另外一个表中行的数量的乘积。
对于from从句中使用假名的情况,比如select u.id,name,age,a.account from utb as u,atb as a where u.id=a.user_id,在我们使用假名之后,那么在该sql语句的任何地方都只能使用假名,不能使用真实的表名,同时上面的as关键字也是可以省略的,也就是说对于上面的语句不能用atb来取代a,utb来取代u了。虽然from从句不是我们指定的第一条语句,但是绝对是第一个被处理的语句,所以在声明假名前使用假名不会导致错误。如果一条from从句引用到两个有着相同名称的表,则必须使用假名。如:
1select p.playerno
2from players as p,players as par
3where par.fn="jp" and par.ln="l" and p.birth_date<par.birth_date
对于多个表间的连接处理可能会导致有相同的结果,即有重复的结果,sql并不会自动从最终结果中删除重复的行,这是如果我们不希望在结果中出现重复的行,那么我们可以在select后直接指定distinct。如:
1select distinct T.playerno
2from teams as T,penalties as pen
3where T.playerno=pen.playerno。
接下来说说连接哈,对于内连接,如果是两个表的话,就取两个表的一个交集,如果是左外连接的话,那就是左边的表全取,右边没有的用null替代,弱国是右外连接的话,那就是右边的表全取,左边没有的用null表示。下面看看一个具体的例子:
1--表stu --表exam
2id name id grade
31, Jack 1, 56
42, Tom 2, 76
53, Kity 11, 89
64, nono
内连接 (显示两表id匹配的)
1select stu.id,exam.id,stu.name, exam.grade from stu (inner) join exam on stu.id=exam.id
2--------------------------------
31 1 Jack 56
42 2 Tom 76
左连接(显示join 左边的表的所有数据,exam只有两条记录,所以stu.id,grade 都用NULL 显示)
1select stu.id,exam.id,stu.name, exam.grade from stu left (outer) join exam on stu.id=exam.id
21 1 Jack 56
32 2 Tom 76
43 NULL Kity NULL
54 NULL nono NULL
右连接(与作连接相反,显示join右边表的所有数据)
1select stu.id,exam.id,stu.name, exam.grade from stu right join exam on stu.id=exam.id
21 1 Jack 56
32 2 Tom 76
4NULL 11 NULL 89
内连接取交集,外连接分左和右,
左连接左边的全取,
右连接右边的全取
对于连接的列的名称相同的话,那么可以使用using来替代条件,如上面的内连接可以这样改写:
1 select stu.id,exam.id,stu.name, exam.grade from stu inner join exam using(id)。
对于左外连接使用的情况一般是当左表的连接列中存在未出现在右表的连接列中的值时,左外连接才有用。
还有个全外连接的,也就是说只要在两个表中出现的记录都会在中间表中出现,当右表有而左表没有或当左表有而右表没有的时候用null表示。具体语法如下:select stu.id,exam.id,stu.name, exam.grade from stu full join exam using(id)。
交叉连接:就是显示求表的笛卡尔积,select * from teams cross join penalties.这句完全等价于select teams.*,penalties.* from teams,penalties.
联合连接:select * from teams union join penalties,这个其实很容易理解,产生结果所包含的列为两个表所有的列和,对于数据的列出,首先列出左表的数据,对于属于右表的列,用null表示,接下来列出右表的数据,对于属于左表的列用null表示。
自然连接:select * from teams nature inner join penalties where division='first';此句完全等同与select t.playerno,t.teamno,t.division,pen.paymentno,pen.payment_date,pen.amount from teams as t inner join penalties as pen on t.playerno=pen.playerno where dividion='first'.相比就知道,我们无须显示指出必须要连接到哪些列,sql会自动查找两表中是否有相同名称的列,且假设他们必须在连接条件中使用。此处的on或using从句是多余的,因此不允许使用。
下面看个例子创建一个称为towns的虚拟表:
1select *
2from (select 'Stratford' as town,4 as number
3 union
4 select 'Plymouth',6
5 union
6 select 'Inglewood',1
7 union
8 select 'Douglas',2) as towns
9order by town;
结果为:
1town number
2----------------------
3Douglas 2
4Inglewood 1
5Plymouth 6
6Stratford 4
posted @
2009-09-24 15:51 你假笨 阅读(2012) |
评论 (0) |
编辑 收藏
本文最先发布于
http://www.lovestblog.cn,请转载的该文者注明文章出处,谢谢合作。
下面简单介绍几种标量函数,也是常用的,我们可以通过类似select abs(-123);的语句来看到我们标量函数的效果。
abs:该函数返回一个数值表达式的绝对值。如abs(-123);
adddate:该函数将一个时间间隔(参数2)添加到时戳或时戳表达式(参数1)中,与此函数同功能的还有date_add。如adddate('2009-01-01',4);结果为2009-01-05。adddate(2009-01-01,interval 5 month);结果为2009-06-01。adddate(timestamp('2009-01-01'),interval 5 month);结果为2009-06-01 00:00:00。adddate('2009-01-01 12:00:00',interval 5 day);结果为2009-01-06 12:00:00。
addtime:把两个时间表达式加起来。如addtime('100:00:00','200:02:04');结果为300:02:04。
ascii:该函数返回一个字符串表达式的第一个字符的ASCII值。
bin:该函数将参数的数值转换为二进制值。
bit_count:该函数显示表示参数的值的位数。如bit_count(3)结果为2。
bit_length:该函数返回字符串值的位长度。如bit_length(bin(2));结果为16
ceiling:该函数返回大于或等于参数值的最大整数。如ceiling(11.11);->12。ceicling(-11.11);->-11
char:该函数返回数值参数的字符串字符,与此函数同功能的还有chr函数。如char(82)+char(105)+char(99)+char(107);->'Rich'
character_length:该函数返回一个字符串表达式的长度,此方法同功能的还有char_length函数。
charset:该函数返回字符串参数的字符集的名称。
coalesce:该函数接受多个参数,返回第一个非null值的参数的值。如coalesce(null,null,'ljp');->'ljp';
concat:该函数合并两个字符串的值。
conv:该函数将一基数为参数2的值(参数1)转换为另一个以参数3为基数的值。如conv(1110,10,16)表示将以10进制的数1110转换成16进制值为456。后面两个参数必须介于2~36之间,否则结果为null,此外参数1的值应该匹配参数2的基数,否则结果为0。
convert:该函数转换参数1的数据类型为参数2指定的类型。参数2必须是一种数据类型,包括binary,char,date,datetime,time,signed,signed integer,unsigned,unsigned integer,varchar。如convert('12.56',unsigned integer);->13。
database:该函数显示当前数据库的名称。
date:该函数将参数变换为一个日期值。如date('2009-01-01 12:00:00');->'2009-01-01'。
datediff:该函数计算两个日期或时间戳表达式间的天数。第一个参数减去第二个参数。
date_sub:该函数从一个日期或时间戳表达式(参数一)中减去一个时间间隔(参数2),与才函数同功能的还有subdate函数。
day:该函数从一个日期或时间戳表达式中返回月的天数,结果总是介于1~31之间的整数,与此函数同功能的还有dayofmonth。
dayname:该函数从一个日期或时间戳表达式中返回一周中某天的名称。
dayofweek:该函数返回一个日期或时间戳表达式中返回某周的天数的序号。该结果总是介于1~7之间的整数。
dayofyear:该函数返回一个日期或时间戳表达式中返回一年中某日的序号。
default:该函数返回参数指定的某列的默认值。
floor:该函数返回小于或等于参数值的最小整数,与ceiling相对。
exp:该函数返回e的x次幕的结果。
format:该函数将一个数值的格式设置为nn,nnn,nnn.nnn的格式。第二个参数表示小数点后的数字个数。
greatest:该函数返回一系列参数中的最大值,和least相对。
hex:如果参数为数字,那么就返回该数字的十六进制表示;如果是字符串,那么将返回每个字符对应的ASCII码。
if:如果第一个参数值为true,那么函数返回第二个参数的值,否则返回第三个参数的值。如if((1>2),"ljp","st");将返回st。
ifnull:如果参数1的值为null,那么返回参数2的值,否则返回参数1的值。如ifnull(null,"ljp");返回"ljp"。
insert:参数4的值放在参数1中由参数2指定的位置,参数3表示参数1中从参数2指定的位置开始接下来的几个字符将被参数4取代。如insert('abcdefgh',4,3,'zzz');->'abczzzgh'。insert('abcdefgh',,4,2,'zzz');->'abczzzfgh'。insert('abcdefgh',4,0,'zzz');->'abczzzdefgh'。insert('abcdefgh',4,-1,'zzz');->'abczzz'。insert('abcdefgh',1,5,'zzz');->'zzzfgh'。
instr:该函数返回参数1内参数2的起始位置。如果为找到,则返回0。如instr('12345',4);->4。
interval:该函数第一个参数指定要插入的值,接下来的参数组成一个升序序列,看第一个参数该插入哪个位置。该函数就是返回该位置。如interval(5,0,1,2,3,6,7);->4表示要把5放在第四个位置(此位置上值为3)之后。
isnull:如果参数值为null,那么返回1,否则返回0。
last_day:该函数返回参数指定的日期或时间戳表达式中月的最后一天,如last_day('2009-01-09');->'2009-01-31'。
lcase:该函数将参数的值的所有大写字母转换为小写字母,与lower同义,与ucase相对。
left:该函数返回一个字符串值参数1的左侧部分,该部分的长度由第二个参数指定。如left("hello world",3);->'hel'。
length:该函数返回一个字符串值的字节长度。如length(null);->null。
ln:该函数返回参数的自然对数,与log同义。
localtime:该函数返回系统日期和时间,localtimestamp与只同义。
locate:该函数返回参数1在参数2内的起点位置。如果参数1在参数2内未出现,则返回0。参数3表示开始搜索的位置。注意instr函数的区别,instr函数是返回参数1内参数2的开始位置。
log2:返回参数以2为底的对数。如log2(64);->6
log10:返回参数以10为底的对数。
lpad:参数3的值填充在参数1的左侧,直到该值的总长度等于参数2的长度。如果最大长度小于参数1的长度,则参数1在左侧被截取。如lpad('data',6,'base');->'badata'。lpad('data',2,'base');->'da'。
ltrim:该函数删除出现在参数前的所有空白,rtrim表示删除参数末尾的所以空白。
makedate:参数2表示天数,他们被添加到参数1中。如makedate(2009,10);->'2009-01-10'。
maketime:三参数分别表示小时,分钟,秒钟。其中分钟和秒钟必须在0~59之间,否则会返回null。
mid:该函数提取参数1中的部分字符串值,参数2标识开始位置,参数3标识字符数。如mid('database',5);->'base'。mid('database',5,2);->'ba'。mid('database',-6);-> 'tabase'。mid('database',-6,3);->'tab'。
minute:该函数从一个时间或时间戳表达式中返回分钟数。
mod:该函数返回两参数相除的余数。如mod(15.4,4,4);->2.2
month:返回时间戳中的月份数,值介于1~12之间。
monthname:该函数从一个日期或时间戳表达式中返回月的名称。如monthname('2009-01-01');->‘April’。
now:返回系统日期和时间。
nullif:如果参数1的值等于参数2的值,那么函数返回null。否则返回参数1的值。
oct:该函数返回八进制参数1的十进制数。如oct(8);->10
ord:该函数返回参数指定的字符串表达式的第一个字符的字符集位置。如ord('Das');->68。
period_add:该函数将月数添加到一个指定的日期,日期格式必须为YYYYMM或YYMM。结果格式为YYYYMM。如period_add('200901',3);->200904。
period_diff:该函数返回两个日期间的月数。如period_diff('200908','200901');->7
PI:返回圆周率。
power:返回参数1的参数2次幂。
quarter:该函数从一个日期或时间戳表达式中返回季度值。结果的值总是介于1~4之间。不过和我们日常生活中的季度不同1~3月为1,4~6月为2,7~9月为3,10~12月为4。
rand:该函数返回0.0和1.0之间的一个随机数。参数表示下一个随机值的计算起点。使用相同的参数值重复调用该函数,结果总是相同的。如cast(rand()*1000 as unsigned integer);
repeat:该函数将参数1的值重复参数2给定的次数。
replace:该函数使参数1指定的字符串中由参数2指定的值替换为参数3指定的值。如replace('data','a','e');->'dete'。
reverse:该函数颠倒一个字符串值中的字符的顺序。
right:该函数返回参数1的右侧部分。该部分长度由第二个参数指定。
round:该函数将一个数字的精度舍入到指定的位数。如round(123.4,-1);->100;round(183.4,-2);->200。
rpad:将参数3的值填充到参数1的右侧,知道值的总长度等于参数2指定的长度,与lpad相对。rpad('data',2,'base')->'da'。
second:该函数返回一个时间或时间戳表达式中的秒数。
sec_to_time:该函数将秒数变换为时间。如sec_to_time((24*60*60)-1);->23:59:59
sign:该函数返回一个数值的字符。sign(50);->1;sign(0)->0;sign(-50)->-1;
space:该函数生成一个空格行,空格个数为参数指定的值。
sqrt:返回参数的平方根值。
strcmp:该函数比较两个字符串表达式的值。如果参数值相等,那么结果为0,如果参数1的值较小,那么返回-1,否则结果为1。
substring:该函数从参数1中减去部分字符串值,参数2给出起始点,参数3给出子付数。如substring('database',5,2);->'ba'。
substring_index:该函数查找参数2表示的值在参数1中的第参数3此出现。如果参数3为正表示从左侧查找,返回从左侧开始找到的该次出现。如果参数3为负,则从右侧开始查找。如substring_index('database','a',3);->'datab';substring_index('database','a',-3);->'tabase';substring_index('database','data',1);->'';substring_index('database','data',-1);->'base'
subtime:该函数对两个时间表达式执行相减操作并返回一个新时间,timediff与此函数功能相似。
time:该函数返回一个时间或时间戳表达式的时间部分。如time('12:13');->12:13:00
time_to_sec:该函数将时间变换为秒数。如time_to_sec('00:16:40');->1000
timestampdiff:该函数计算两个日期或时间戳表达式间的时间。参数1表示时间间隔单元,如day,month,year,quarter,week,hour,minute,second,frac_second,参数2和参数3形成两个表达式。如timestampdiff(day,'2009-01-01','2009-01-04');->4.
timestamp:该函数将参数1变换为一个时间戳,如果指定了参数2,则它应该是一个时间表达式,且会被添加到参数1的值中。
timestampadd:该函数将时间间隔添加到一个日期或时间戳表达式。参数1表示时间间隔的单元,参数2表示天数或月数等,参数3表示时间间隔添加到的表达式。如timestampadd(DAY,2,'2009-01-01');->'2009-01-03';timestampadd(MONTH,2,'2009-01-01');->"2009-03-01"。
trim:该函数删除参数1表示的字符串值中开始和最后的所有空格。
truncate:该函数将数字截断到指定的小数位数,注意和round的区别,round是四舍五入,而truncate是截断。如truncate(123.45,-1);->120。truncate(123.375,1);->123.3。
unhex:与hex相对,将十六进制表示的参数转换为相应的字符。如unhex(hex('hello'))'->hello
ucase:类似upper,都是将参数中的所有小写字母转换为大写字母。
week:该函数从一个日期或时间戳表达式中返回周数,类似的函数还有weekofyear。结果介于1~53之间的一个整数。如week('2009-06-07');->23
weekday:该函数返回一周中的天数。结果为介于0~6之间的数。0表示星期一。
year:该函数从一个日期或时间戳表达式中返回年数。
yearweek:如果指定参数1,则该函数从一个时间戳或日期表达式中返回格式为YYYYWW的年份及周数。周数的范围为01~52之间。如yearweek('2009-07-06');->200927
posted @
2009-09-23 16:54 你假笨 阅读(1469) |
评论 (1) |
编辑 收藏
(为了方便java学习者使用OsWorkflow,特用flex设计了此设计器,欢迎大家下载使用。亦欢迎大家光临我的个人博客http://www.lovestblog.cn)前两天和一网友聊天的时候,他强烈建议我把这个工作流设计器好好完善下,本来学校项目的需求基本已经满足了,但是离完善实在差距太远,于是花了两天时间在原有基础上进行了下改进,现在得工作流设计器比以前的版本多了几个功能:
1. 导出文件请选择文件-->>导出选项,导出文件保存时请您务必加上xml的后缀
2. 鼠标移到直线上的时候,直线会初始化显示为绿色,按住鼠标不放,拖动鼠标,将会在直线上出现一个拐点,该拐点可以随便拖动,双击拐点会自动删除该拐点,也可用框选选中拐点进行删除,选中的拐点,初始颜色为蓝色,您可以自由设置,移开时直线会恢复为粉红色
3. 可用框选选中组件进行删除,如果为半透明状态,则表明为选中,您同时可以按住ctrl键,选中其他没有被选中的组件,从而进行进行加选
4. 如果您本选中了某组件,然后按住ctrl键再将其框选,则该组件会被取消选中
5. 点击鼠标右键有备选菜单进行操作
6. 下面的Outline是临时生成的xml文件,您可以在不导出文件的情况下查看现有的xml文件
7. 选择子元素步骤操作之后,只有当鼠标在开始节点或步骤节点下面的action列表中点击时才会新增一个action操作
8. 合并节点只能有一个无条件连接进行连出,合分支节点只能连出无条件连接,且可多个
9.根据导入的文件生成得流程图不具备定位的功能,因为我觉得是多余的,只要它们之间的关系明确得话,那你再在界面上进行拖拉成你喜欢得样式就可以了,所以当你导入文件的时候,看到的会是每个节点随机选择位置。
以上是我在此版本中进行的系统说明,请见关于--》系统说明。
再您下载我附件的同时,请先到
http://get.adobe.com/cn/air/处下载AdobeAIRInstaller.exe文件进行安装,使您系统能进行AIR文件的安装,附件为AIR格式文件。
/Files/nijiaben/OsWorkflow.rar
posted @
2009-09-05 18:28 你假笨 阅读(1926) |
评论 (1) |
编辑 收藏
欢迎大家提出意见,多余的话就不多说了,花了10天的作品,辛苦啊由于有400多k,所以大家在看到下面效果前,先给大家几张截图哈,如果感兴趣再去捣鼓一下那东西呵。也欢迎各位到我个人博客上留言哈,
http://www.lovestblog.cn
这里好像不能插入flash,如果大家有兴趣的话,可以去
http://www.lovestblog.cn/articlePicture/84/84.1.swf体验下真实的效果。
posted @
2009-07-31 23:52 你假笨 阅读(6751) |
评论 (44) |
编辑 收藏
这个暑假本来打算去广州一公司实习的,结果接到老师的一个项目,是关于工作流的,实现一个文件审批的流程,起初也不知道是怎么回事,老师也有些事情,就抛下一句话“去下载OSWorkflow的客户端下来看看”,结果下载下来才知道是怎么回事,要求用Flex实现它,我的妈呀,这个可是一个不小的工程,还得我一个人完成,上面这个项目也批下来了,钱都拨下来了,不完成不行啊,巧合的是自己这个暑假又有一个培训,根本没什么时间去做呀,就在前几天突然决定暂时放弃培训,先把这个完成再说,在做的时候没什么底,不知道自己能不能完成,因为感觉很多东西我都不会。不管怎样还是要试一下不,我就喜欢尝试下,往往在尝试中能发现点什么,这不从19号开始就衣食住行都在学校实验室了,到今天界面上的功能基本实现了大部分了,至少能拖组件,然后在组件间能按照一定的要求进行连接,比如说从合并节点出来的只能是无条件连接到节点或这操作,每个操作最多只能有一个非条件连接,连线的终点只能是节点等等,我没有研究过OsWorkflow的源码,但是我从提供给我的客户端以及生成的xml文件推断出一些规则,于是经过不久的思考就开始动工了,慢慢的雏形也就出来了,当中碰到了不少问题,当然也慢慢解决了,等完成之后再把代码优化下,到时觉得可以的话,可以开源,上次我那博客
http://www.lovestblog.cn本来也打算开源的,但是确实有点担心,怕放上来,被高人们唾骂,怕承受不了巨大的打击,就还是先放放了,再者也没时间去优化代码,所以等有时间了再整理下再拿出来挨批了,呵呵,好了说了那么多废话了,还是把这个工作流的一个截图拿出来晒晒吧,等全部完成之后在拿出来,希望能听到大家宝贵的意见。
posted @
2009-07-24 23:30 你假笨 阅读(2150) |
评论 (2) |
编辑 收藏
本文最先发布于本人个人博客
http://www.lovestblog.cn
下面简单的说说归并排序,所谓归并排序就是说把输入数组分成两组当然也可以大于2组,一般我们是等量的分成2组,通过递归我们可以把长度为n的数组分成n个数组,我们通过一定的关键字比较把两两结合成一个有序的数组,然后回溯到原数组大小的有序数组,具体的我就不多说了,因为比较简单,到网上可以找些相关文章看看什么是归并排序,归并排序算法可以再O(nlogn)的时间内对长度为n的序列完成排序,至于合并两个有序数组,假如这两个数组的长度分别为m和n,那么我们只需要O(n+m)的时间久可以完成对这两个有序数组的合并,下面还是代码说明之:
package org.rjb.Sort;
/** *//**
* 归并排序(升序排列)
* @author ljp
*
*/
public class MergeSort {
/** *//**
* 对原始数组进行平等划分为两个子数组
* @param nums
*/
public static void sort(int[] nums){
int n=nums.length;
if(n<=1)
return;
int nums1[]=new int[n/2];
int nums2[]=new int[n-n/2];
for(int i=0,j=nums1.length;j<nums.length;i++,j++){
if(i<nums1.length){
nums1[i]=nums[i];
}
nums2[i]=nums[j];
}
//递归对子数组进行划分
sort(nums1);
sort(nums2);
//把子数组排序后的结果进行合并
merge(nums,nums1,nums2);
}
/** *//**
* 合并两个有序的子数组为一个有序的数组
* @param nums 合并之后的数组
* @param num1 有序的子数组
* @param num2 有序的子数组
*/
public static void merge(int[] nums,int num1[],int num2[]){
int n1=num1.length-1;
int n2=num2.length-1;
int k=0;
int k1=0,k2=0;
while(k1<=n1||k2<=n2){
int e=0;
if(k1>n1){//如果第一个数组已经全部比较完了,那么我们只要直接复制第二个数组的条目到合并数组中即可
e=num2[k2++];
}else if(k2>n2){//如果第二个数组已经全部比较完了,那么我们只要直接复制第一个数组的条目到合并数组中即可
e=num1[k1++];
}else if(num1[k1]>num2[k2]){//把比较的两个条目中关键值小的放到合并数组中
e=num2[k2++];
}else{
e=num1[k1++];
}
nums[k++]=e;
}
}
/** *//**
* 主函数
* @param args
*/
public static void main(String args[]){
int[] nums={10,2,3,7,4,9,1};
sort(nums);
for(int i=0;i<nums.length;i++){
System.out.print(nums[i]+" ");
}System.out.println();
}
}
posted @
2009-05-29 16:55 你假笨 阅读(1215) |
评论 (0) |
编辑 收藏
摘要: 本文最先发布在我的个人博客http://www.lovestblog.cn
文字转载自http://jaskell.blogbus.com/logs/3272503.html,代码是自己写的一个测试类。
&nbs...
阅读全文
posted @
2009-05-28 22:14 你假笨 阅读(1249) |
评论 (0) |
编辑 收藏
摘要: 本文最先发表在本人的个人博客http://www.lovestblog.cn
先把题目晒出来,这个题目不是很难,但是当时仅仅因为输出的问题折腾了我大半天,在ACM提供的运行环境中只有到最后才能把结果输出,不能在中途就把结果输...
阅读全文
posted @
2009-05-26 11:00 你假笨 阅读(1744) |
评论 (0) |
编辑 收藏
本文最先发表在本人个人java+flex技术博客http://www.lovestblog.cn,欢迎大家光临。(转载的请不要删除该行,谢谢合作)
这两天接了一个网站,比较简单两三天就基本搞定了,但是其中碰到最难的就是flex的一个中文问题了,下面我主要想讲讲三种不同的现象。
- 第一种: Image组件的源地址是中文的,比如resources/数学/高等数学/math.jpg;
tomcat中的server.xml中配置端口的那段加上 URIEncoding="utf-8";
直接访问资源地址如:http://localhost:8080/WebTest/resources/数学/高等数学/math.jpg;
这种情况下Image组件不能显示出来,下面直接访问的地址能访问到数据。
- 第二种: Image组件的源地址是GBK的,比如比如resources/数学/高等数学/math.jpg;
tomcat中的server.xml中配置端口的那段加上 URIEncoding="GBK";
直接访问资源地址如:http://localhost:8080/WebTest/resources/数学/高等数学/math.jpg;
这种情况下Image组件式能显示出来的,但是直接访问的那个地址是不能访问到数据的。
- 第三种: mage组件的源地址是utf-8的,比如resources/%E6%95%B0%E5%AD%A6/%E9%AB%98%E7%AD%89%E6%95%B0%E5%AD%A6/math.jpg;
tomcat中的server.xml中配置端口的那段加上 URIEncoding="utf-8";
直接访问资源地址如:http://localhost:8080/WebTest/resources/数学/高等数学/math.jpg;
这种情况下Image组件式能显示出来的,直接访问的那个地址是也能访问到数据。
原因分析:
浏览器默认的编码方式是utf-8的,flex中地址默认是采用utf-8的,而tomcat默认的编码方式是ISO-8859-1的,即我们访问的地址都是iso-8859-1编码的,如果不设置tomcat中的编码方式即为默认的iso-8859-1方式,那么浏览器中的请求地址中的中文是不能被解析的,所以请求不到资源,因此,我们通过设置tomcat的编码方式为utf-8即可以通过浏览器访问到含有中文名的资源。同理默认情况下flex组件也访问不到带有中文路径的资源;
如果tomcat设置为utf-8的,我们可以访问http://localhost:8088/EncodingTest/resource/未命名.jpg类似的地址,但是对于flex中<mx:Image source="resources/体育/足球/1.jpg" />这样的组件还是显示不出来(这点我也疑惑,还望高人指点),但是我们设置为<mx:Image source="resources/%E4%BD%93%E8%82%B2/%E8%B6%B3%E7%90%83/1.jpg" />这样我们就能访问到了。
如果tomcat编码方式设置为GBK的话,对于flex组件<mx:Image source="resources/体育/足球/1.jpg" />我们是可以访问到的,但是对于<mx:Image source="resources/%E4%BD%93%E8%82%B2/%E8%B6%B3%E7%90%83/1.jpg" />这样的我们是访问不到的,对于浏览器中的地址http://localhost:8088/EncodingTest/resource/未命名.jpg,我们是访问不到的,但是对于我们把未命名进行GBK编码之后的%CE%B4%C3%FC%C3%FB替换了,即http://localhost:8088/EncodingTest/resource/%CE%B4%C3%FC%C3%FB.jpg就能访问了。至于如何取得中文的GBK编码我们可以通过java方法取得,比如String s="未命名.jpg";s=java.net.URLEncoder.encode(s,"GBK");这样就取得了“未命名.jpg”的GBK编码了。
总结如下:
总结出了一个基本解决中文编码的方法,即tomcat中设置编码为utf-8,flex中组件要访问资源的路径如果带有中文那么我们去把中文转换成utf-8格式的在赋值给组件的source属性,对于浏览器中访问的地址就可以是带有中文的访问地址了。
posted @
2009-04-30 01:35 你假笨 阅读(1700) |
评论 (1) |
编辑 收藏
本文最初发布于本人的flex博客http://www.lovestblog.cn/,欢迎大家光临。(转载的请不要删除该行,谢谢合作)
我们都知道jQUery对象中有一个类数组的元素包装集,该集合类似js中的数组一样拥有length属性,因此我们称此为类数组,下面我们就来总结下这个jQuery对象中的类数组时如何进行操作的,看看我们的jQuery为我们都提供了哪些可用的方法:
size():很明显,它应该是返回包装集中的元素个数,如$('a').size()表示链接元素的个数;
get(index):当没指定index时就默认取包装集中所有元素,并以js中的数组形式返回,如果指定了index,则返回下标为index对应的元素,如$('img[title]').get(0)返回包含属性title的第一个img元素,其也等效于$('img[title]')[0];
index(elem):在包装集中返回元素elem所在的下标,如果没找到该元素则返回-1;
add(String|elem|Array):把参数中的元素添加到包装集中,如果参数是jQuery选择器,那么将把所有匹配的对象都添加到集合中,如果是html元素那就通过clean方法得到的元素数组添加到集合中,如果是dom元素或dom元素数组,那就直接添加到集合了;注意返回的是添加后的包装集;如$('img[alt]','img[title]')等效于$('img[alt]').add('img[title]')即返回包含了alt属性的img元素或包含了title属性的img元素;
not(String|elem|Array):把包装集中满足参数条件的元素删除,注意参数只能是筛选表达式,即以"["或者":"开头的表达式,如$('img[title]').not('title*=puy')即返回包含title属性的img元素,并且这些元素的title属性中包含有puy文本;返回的是筛选之后的包装集;
filter(String|function):如果传入的参数是String类型的话,那么该表达式必须也是筛选表达式,用于从包装集里删除所有与选择器不匹配的元素;如果传入的是一个函数的话,那么包装集中的每个元素都调用这个函数,若这个函数返回false则把这个元素从包装集中删除,而在函数中可以通过this关键字来调用当时包装集中调用方法的元素;如$('td').filter(function(){return this.innerHTML.match(/^"d+$/)})返回td中的内容为数字的所有td元素;
slice(begin,end):创建并返回新的包装集,该包装集是原来包装集的连续的一部分,且新包装集的第一个元素是原包装集中的begin位置的元素,而最后一个元素是end位置元素的前一元素,当然end可以不指定,那么将延伸到原始包装集的末尾;如$('*').slice(2,3)这个语句选择页面上的所有元素,然后生存包含原始包装集的第三个元素的新包装集,注意这个$('*').get(2)不同,这个返回的是元素,而slice方法返回的是包装集,从而拥有包装集的操作;
childen():返回原始包装集元素的所有不同子元素所组成的新包装集(不包含文本节点),如$('div').children()返回所有div元素下的子元素所组成的新包装集;如果指定了参数,那么该参数也是筛选表达式;
contents():返回原始包装集元素的内容新包装集(可以包含文本节点);注意此方法不能接受参数进行过滤;
next():返回原始包装集元素的所有唯一的下一个兄弟元素所组成的新包装集;如果指定了参数,那么该参数也是筛选表达式;如$('div#someDiv').next()返回包含id为someDiv的div元素的下一个兄弟元素的包装集;如果指定了参数,那么该参数也是筛选表达式;
nextAll():返回包含原始包装集元素的所有后续兄弟的新包装集;如$('div#someDiv').nextAll()返回包含id为someDiv的div元素的后面兄弟元素的新包装集;如果指定了参数,那么该参数也是筛选表达式;
parent():返回原始包装集所有元素的唯一直接父元素的新包装集;如果指定了参数,那么该参数也是筛选表达式;
parents():返回原始包装集所有元素的祖先元素的新包装集;如果指定了参数,那么该参数也是筛选表达式;
prev():返回原始包装集元素的所有唯一的上一个兄弟元素组成的新包装集;如果指定了参数,那么该参数也是筛选表达式;
prevAll():返回包含原始包装集元素的所有前面兄弟元素的新包装集;如果指定了参数,那么该参数也是筛选表达式;
siblings():返回包含原始包装集元素中的所有唯一兄弟元素所组成的新包装集;如果指定了参数,那么该参数也是筛选表达式;
find(String):返回包含原始包装集里与传入的选择器表达式相匹配的所有元素的新包装集,并且原始包装集中的元素的后代也会被传入新的包装集;
contains(text):返回包含text参数所传入的文本字符串的元素所组成的新包装集;
is(String):如果包装集中含有String匹配的元素,那么返回true,否则返回false;
clone(copyHandle):如果传入的参数为true,那么会连带事件一起拷贝,否则不拷贝事件,形成一个新的包装集;
end():在jQuery命令链内调用,以便返回退到前一个包装集;
andSelf():合并命令链内最近产生的两个包装集;
对于包装元素的操作就总结到这里,如果哪里不对的还请各位指出来方便大家参考学习。
posted @
2009-04-22 10:50 你假笨 阅读(2387) |
评论 (0) |
编辑 收藏