Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

未正常毕业*Cardiff卡迪夫大学毕业`等证件`材料证书

$
0
0
*卡迪夫大学毕业证】QQ/微信:549585563  联系人:Kimi 代办国外(海外)澳洲英国 加拿大 韩国 美国 新西兰 等各大学毕业证,修改成绩单分数,学历认证,文凭,diploma,degree
 
 
 
欢迎咨询!QQ/微信:549585563,专业为留学生提供毕业证、学历认证、文凭、学位证、学位证书、使馆公证、国外学历学位教育部认证、使馆留学回国人员证明、录取通知书、Offer、在读证明、雅思托福成绩单、网上存档永久可查!【实体公司,寰宇教育,值得信赖】
  
   一、【主营项目】:
1.毕业证、成绩单、使馆认证、教育部认证、留信、学生卡-- OFFER等.等!
 
2.办理真实使馆公证(即留学回国人员证明,不成功不收费)
 
3.教育部国外学历学位认证咨询。(网上可查、永久存档、快速稳妥)
 
4.办理各国各大学文凭(一对一专业服务,可全程监控跟踪进度)








咨询顾问:Kimi QQ/微信:549585563 
 
1、挂科了,不想读了,成绩不理想怎么办??
2、找工作没有文凭怎么办?有本科却要求硕士又怎么办?
3、打算回国了,找工作的时候,需要提供认证,有文凭却得不到认证。又该怎么办???
 
如果您是以下情况,我们都能竭诚为您解决实际问题:
1、在校期间,因各种原因未能顺利毕业,拿不到官方毕业证; 
2、面对父母的压力,希望尽快拿到;   
3、不清楚流程以及材料该如何准备;   
4、回国时间很长,忘记办;   
5、回国马上就要找工作,办给用人单位看;  
6、企事业单位必须要求办的; 
德国大学:慕尼黑工业大学,哥廷根大学,慕尼黑大学,开姆尼茨工业大学,卡尔斯鲁厄大学,达姆斯塔特工业大学,明斯特大学,弗赖堡大学,多特蒙德工业大学,马堡大学,杜塞尔多夫大学,波鸿鲁尔大学,布伦瑞克工业大学,奥格斯堡大学,杜伊斯堡埃森大学,凯撒斯劳滕工业大学,法兰克福大学,亚琛工业大学,斯图加特大学,汉诺威大学,基尔大学,柏林自由大学,柏林工业大学,吉森大学,纽伦堡大学,莱比锡大学,美因茨大学,乌尔兹堡大学,萨尔大学,科隆大学,不来梅大学,奥登堡大学,安哈尔特应用技术大学,波恩大学,勃兰登堡工业大学,德累斯顿工业大学,汉堡大学,柏林洪堡大学,卡塞尔大学,克劳斯塔尔工业大学,罗斯托克大学,耶拿应用技术大学,汉堡音乐和戏剧学院,鲁昂大学,克莱蒙费朗一大,克莱蒙费朗第二大学,萨瓦大学,佩皮尼昂大学,南布列塔尼大学,巴黎第一大学,第戎大学,国立里昂第二大学,格勒诺布尔第三大学,凡尔赛大学,巴黎第九大学,马赛大学,昂热大学,贝桑松大学,波城大学,滨海大学,科西嘉大学,尼斯大学,巴黎第八大学,南锡一大,雷恩一大,巴黎第四大学,卡昂大学,蒙彼利埃三大,蒙彼利埃第一大学,图尔大学,INSEEC,图卢兹第一大学,图卢兹第三大学,巴黎第四大学索邦大学,斯特拉斯堡大学,图卢兹三大,波尔多一大,里尔第三大学,里昂三大,奥尔良大学,亚眠大学,罗马二大,米兰大学,马兰欧尼,办理德国毕业证文凭学历认证成绩单留学回国证明
 
 
英国大学:
纽卡斯尔大学,帝国理工学院,巴斯大学,埃克塞特大学,伦敦大学学院UCL,华威大学,约克大学,兰卡斯特大学,萨里大学,莱斯特大学,布里斯托大学,伯明翰大学,格鲁斯特大学,谢菲尔德大学,南安普顿大学,拉夫堡大学,爱丁堡大学,诺丁汉大学,伦敦大学亚非学院SOAS,格拉斯哥大学,曼彻斯特大学,伦敦国王学院KCL,皇家霍洛威大学RHUL,阿斯顿大学,利兹大学,萨塞克斯大学,卡迪夫大学,伦敦艺术大学,雷丁大学,肯特大学,利物浦大学,伦敦玛丽女王学院QMUL,赫瑞瓦特大学,埃塞克斯大学,阿伯丁大学,伦敦城市大学,斯特拉思克莱德大学,基尔大学,考文垂大学,斯旺西大学,邓迪大学,阿伯泰大学,切斯特大学,朴茨茅斯大学,威尔士班戈大学,林肯大学,布拉德福德大学,北安普顿大学,诺丁汉特伦特大学,诺森比亚大学,赫尔大学,约克圣约翰大学,哈德斯菲尔德大学,伯恩茅斯大学,伦敦商学院大学,罗汉普顿大学,爱丁堡玛格丽特皇后学院,格林威治大学,赫特福德大学,布鲁内尔大学,德蒙福特大学,罗伯特戈登大学RGU,索尔福德大学,桑德兰大学,威斯敏斯特大学,南岸大学,圣安德鲁斯大学,普利茅斯大学,牛津布鲁克斯大学,伯明翰城市大学BCU,办理英国毕业证文凭学历认证成绩单留学回国证明
 
 
澳洲大学:
梅西大学,林肯大学,奥塔哥大学,奥克兰理工大学AUT,怀卡托大学,基督城理工学院CPIT,马努卡理工学院,坎特伯雷大学,奥克兰大学,奥克兰商学院AIS,悉尼大学USYD,新南威尔士大学UNSW,查尔斯达尔文大学CDU,澳大利亚联邦大学,斯威本科技大学Swinburne,巴拉瑞特大学ballarat,RMIT,墨尔本大学,阿德莱德大学Adelaide,莫纳什大学Monash,昆士兰大学UQ,西澳大学UWA,澳大利亚国立大学ANU,麦考瑞大学Macquarie,纽卡斯尔大学,卧龙岗大学
Wollongong,格里菲斯大学Griffith,弗林德斯大学Flinders,塔斯马尼亚大学UTAS,堪培拉大学,邦德大学Bond,迪肯大学Deakin,悉尼科技大学UTS,科廷大学Curtin,墨尔本皇家理工学院RMIT,昆士兰科技大学QUT,拉筹伯大学La Trobe,莫道克大学Murdoch,澳洲TAFE,南澳大学UniSA,中央昆士兰大学CQU,詹姆斯库克大学JCU,新英格兰大学UNE,南昆士兰大学USQ,埃迪斯科文大学ECU,南十字星大学SCU,阳光海岸大学,维多利亚大学Victoria,办理澳洲毕业证文凭学历认证成绩单留学回国证明
 
 
美国大学:
俄亥俄州立大学OSU,加州大学洛杉矶分校UCLA,华盛顿州立大学WSU,普渡大学Purdue,俄勒冈大学Oregon,纽约大学NYU,西雅图大学Seattle,南加州大学USC,宾州州立大学PSU,匹兹堡大学PITT,加州理工学院CIT,西北大学NWU,
宾夕法尼亚大学Pennsylvania,密歇根州立大学MSU,密歇根大学UMICH,波士顿大学BU,德克萨斯大学奥斯汀分校utexas,哈佛大学Harvard,麻省理工学院MIT,田纳西大学UTK,帕森斯设计学院Parsons,佩斯大学Pace,普林斯顿大学Princeton,托莱多大学Toledo,杜克大学Duke,芝加哥大学Chicago,达特茅斯学院Dartmouth,拉文大学La Verne,康奈尔大学Cornell,约翰霍普金斯大学JHU,布朗大学Brown,莱斯大学Rice,埃默里大学Emory,圣母大学,范德堡大学Vandy,加州大学伯克利分校UCB,卡内基梅隆大学CMU,乔治城大学Georgetown,弗吉尼亚大学UVa,塔夫斯大学Tufts,维克森林大学WFU,布兰迪斯大学Brandeis,威廉玛丽学院wm,波士顿学院BC,佐治亚理工学院Gatech,利哈伊大学Lehigh,罗切斯特大学Rochester,威斯康星大学WISC,内布拉斯加大学UNL,伦斯勒理工学院RPI,华盛顿大学UW,加州大学戴维斯分校UCD,加州大学欧文分校UCI,加州大学UCSB,天普大学Temple,叶史瓦大学Yeshiva,肯塔基大学Kentucky,乔治华盛顿大学GWU,雪城大学SU,马里兰大学UMD,佩珀代因大学Pepperdine,乔治亚大学UGA,克莱姆森大学Clemson,福特汉姆大学Fordham,明尼苏达大学UMN,迈阿密大学UM,密西西比大学Mississippi,南卫理公会大学SMU,康涅狄格大学Connecticut,爱荷华大学Iowa,印地安那大学伯明顿分校IUB,特拉华大学UD,伍斯特理工学院WPI,贝勒大学baylor,马凯特大学Marquette,纽约宾汉姆顿大学binghamton,纽约奥尔巴尼大学Albany,克拉克大学Clark,科罗拉多大学CU-Boulder,密苏里大学Missouri,堪萨斯大学KU,北卡罗来纳州立大学NCSU,俄亥俄大学ohio,俄克拉荷马大学Oklahoma,德州A&M大学TAMU,佛罗里达州立大学FSU,斯坦福大学Stanford,加州大学圣地亚哥分校UCSD,凤凰城大学UPX,旧金山大学USF,休斯敦大学UH,斯蒂文斯理工学院SIT,阿拉巴马大学Alabama,塔尔萨大学TU,德雷塞尔大学Drexel,爱荷华州立大学ISU,加州大学河滨分校UCR,丹佛大学DU,堪萨斯州立大学KSU,罗格斯大学Rutgers,佛蒙特大学UVM,奥本大学Auburn,美国东北大学NEU,纽约州立大学石溪分校SBU,亚利桑那州立大学ASU,亚利桑那大学UA,加州大学圣克鲁兹分校UCSC,纽约州立大学布法罗分校Buffalo,纽约理工学院NYIT,北卡罗莱纳大学UNC,罗德岛设计学院RISD,加州旧金山分校UCSF,伊利诺伊大学香槟分校UIUC,杜兰大学Tulane,社区大学College,阿肯色大学,犹他大学,杨百翰大学BYU,辛辛那提大学,霍夫斯特拉大学,肯特州立大学,旧金山艺术大学AAU,莱特州立大学,欧道明大学,罗德岛大学URI,南达科他州立大学,阿肯色大学小石城分校,长岛大学布鲁克林校区,海斯堡州立大学FHSU,圣莫尼卡社区学院SMC,办理美国毕业证文凭学历认证成绩单留学回国证明
 
 
加拿大大学:
多伦多大学,约克大学York,渥太华大学,西安大略大学UWO,滑铁卢大学,麦克马斯特大学McMaster,卡尔顿大学,皇后大学,布鲁克大学,湖首大学,BCIT,温莎大学,瑞尔森大学,百年理工学院,特伦特大学,英属哥伦比亚大学UBC,西蒙菲莎大学SFU,昆特兰理工大学KPU,汤普森河大学TRU,西三一大学,阿尔伯塔大学,卡尔加里大学,里贾纳大学,阿卡迪亚大学,达尔豪斯大学,圣玛丽大学,麦吉尔大学,康考迪亚大学,菲沙河谷大学UFV,蒙特利尔大学,温尼伯大学,曼尼托巴大学,毕业证加拿大文凭学历认证成绩单留学回国证明
未正常毕业*Cardiff卡迪夫大学毕业`等证件`材料证书
作者:qiangpfeg 发表于2016/12/12 20:09:07 原文链接
阅读:14 评论:0 查看评论

未正常毕业*UCLan中央兰开夏大学毕业`等证件`材料证书

$
0
0
*中央兰开夏大学毕业证】QQ/微信:549585563  联系人:Kimi 代办国外(海外)澳洲英国 加拿大 韩国 美国 新西兰 等各大学毕业证,修改成绩单分数,学历认证,文凭,diploma,degree
 
 
 
欢迎咨询!QQ/微信:549585563,专业为留学生提供毕业证、学历认证、文凭、学位证、学位证书、使馆公证、国外学历学位教育部认证、使馆留学回国人员证明、录取通知书、Offer、在读证明、雅思托福成绩单、网上存档永久可查!【实体公司,寰宇教育,值得信赖】
  
   一、【主营项目】:
1.毕业证、成绩单、使馆认证、教育部认证、留信、学生卡-- OFFER等.等!
 
2.办理真实使馆公证(即留学回国人员证明,不成功不收费)
 
3.教育部国外学历学位认证咨询。(网上可查、永久存档、快速稳妥)
 
4.办理各国各大学文凭(一对一专业服务,可全程监控跟踪进度)








咨询顾问:Kimi QQ/微信:549585563 
 
1、挂科了,不想读了,成绩不理想怎么办??
2、找工作没有文凭怎么办?有本科却要求硕士又怎么办?
3、打算回国了,找工作的时候,需要提供认证,有文凭却得不到认证。又该怎么办???
 
如果您是以下情况,我们都能竭诚为您解决实际问题:
1、在校期间,因各种原因未能顺利毕业,拿不到官方毕业证; 
2、面对父母的压力,希望尽快拿到;   
3、不清楚流程以及材料该如何准备;   
4、回国时间很长,忘记办;   
5、回国马上就要找工作,办给用人单位看;  
6、企事业单位必须要求办的; 
德国大学:慕尼黑工业大学,哥廷根大学,慕尼黑大学,开姆尼茨工业大学,卡尔斯鲁厄大学,达姆斯塔特工业大学,明斯特大学,弗赖堡大学,多特蒙德工业大学,马堡大学,杜塞尔多夫大学,波鸿鲁尔大学,布伦瑞克工业大学,奥格斯堡大学,杜伊斯堡埃森大学,凯撒斯劳滕工业大学,法兰克福大学,亚琛工业大学,斯图加特大学,汉诺威大学,基尔大学,柏林自由大学,柏林工业大学,吉森大学,纽伦堡大学,莱比锡大学,美因茨大学,乌尔兹堡大学,萨尔大学,科隆大学,不来梅大学,奥登堡大学,安哈尔特应用技术大学,波恩大学,勃兰登堡工业大学,德累斯顿工业大学,汉堡大学,柏林洪堡大学,卡塞尔大学,克劳斯塔尔工业大学,罗斯托克大学,耶拿应用技术大学,汉堡音乐和戏剧学院,鲁昂大学,克莱蒙费朗一大,克莱蒙费朗第二大学,萨瓦大学,佩皮尼昂大学,南布列塔尼大学,巴黎第一大学,第戎大学,国立里昂第二大学,格勒诺布尔第三大学,凡尔赛大学,巴黎第九大学,马赛大学,昂热大学,贝桑松大学,波城大学,滨海大学,科西嘉大学,尼斯大学,巴黎第八大学,南锡一大,雷恩一大,巴黎第四大学,卡昂大学,蒙彼利埃三大,蒙彼利埃第一大学,图尔大学,INSEEC,图卢兹第一大学,图卢兹第三大学,巴黎第四大学索邦大学,斯特拉斯堡大学,图卢兹三大,波尔多一大,里尔第三大学,里昂三大,奥尔良大学,亚眠大学,罗马二大,米兰大学,马兰欧尼,办理德国毕业证文凭学历认证成绩单留学回国证明
 
 
英国大学:
纽卡斯尔大学,帝国理工学院,巴斯大学,埃克塞特大学,伦敦大学学院UCL,华威大学,约克大学,兰卡斯特大学,萨里大学,莱斯特大学,布里斯托大学,伯明翰大学,格鲁斯特大学,谢菲尔德大学,南安普顿大学,拉夫堡大学,爱丁堡大学,诺丁汉大学,伦敦大学亚非学院SOAS,格拉斯哥大学,曼彻斯特大学,伦敦国王学院KCL,皇家霍洛威大学RHUL,阿斯顿大学,利兹大学,萨塞克斯大学,卡迪夫大学,伦敦艺术大学,雷丁大学,肯特大学,利物浦大学,伦敦玛丽女王学院QMUL,赫瑞瓦特大学,埃塞克斯大学,阿伯丁大学,伦敦城市大学,斯特拉思克莱德大学,基尔大学,考文垂大学,斯旺西大学,邓迪大学,阿伯泰大学,切斯特大学,朴茨茅斯大学,威尔士班戈大学,林肯大学,布拉德福德大学,北安普顿大学,诺丁汉特伦特大学,诺森比亚大学,赫尔大学,约克圣约翰大学,哈德斯菲尔德大学,伯恩茅斯大学,伦敦商学院大学,罗汉普顿大学,爱丁堡玛格丽特皇后学院,格林威治大学,赫特福德大学,布鲁内尔大学,德蒙福特大学,罗伯特戈登大学RGU,索尔福德大学,桑德兰大学,威斯敏斯特大学,南岸大学,圣安德鲁斯大学,普利茅斯大学,牛津布鲁克斯大学,伯明翰城市大学BCU,办理英国毕业证文凭学历认证成绩单留学回国证明
 
 
澳洲大学:
梅西大学,林肯大学,奥塔哥大学,奥克兰理工大学AUT,怀卡托大学,基督城理工学院CPIT,马努卡理工学院,坎特伯雷大学,奥克兰大学,奥克兰商学院AIS,悉尼大学USYD,新南威尔士大学UNSW,查尔斯达尔文大学CDU,澳大利亚联邦大学,斯威本科技大学Swinburne,巴拉瑞特大学ballarat,RMIT,墨尔本大学,阿德莱德大学Adelaide,莫纳什大学Monash,昆士兰大学UQ,西澳大学UWA,澳大利亚国立大学ANU,麦考瑞大学Macquarie,纽卡斯尔大学,卧龙岗大学
Wollongong,格里菲斯大学Griffith,弗林德斯大学Flinders,塔斯马尼亚大学UTAS,堪培拉大学,邦德大学Bond,迪肯大学Deakin,悉尼科技大学UTS,科廷大学Curtin,墨尔本皇家理工学院RMIT,昆士兰科技大学QUT,拉筹伯大学La Trobe,莫道克大学Murdoch,澳洲TAFE,南澳大学UniSA,中央昆士兰大学CQU,詹姆斯库克大学JCU,新英格兰大学UNE,南昆士兰大学USQ,埃迪斯科文大学ECU,南十字星大学SCU,阳光海岸大学,维多利亚大学Victoria,办理澳洲毕业证文凭学历认证成绩单留学回国证明
 
 
美国大学:
俄亥俄州立大学OSU,加州大学洛杉矶分校UCLA,华盛顿州立大学WSU,普渡大学Purdue,俄勒冈大学Oregon,纽约大学NYU,西雅图大学Seattle,南加州大学USC,宾州州立大学PSU,匹兹堡大学PITT,加州理工学院CIT,西北大学NWU,
宾夕法尼亚大学Pennsylvania,密歇根州立大学MSU,密歇根大学UMICH,波士顿大学BU,德克萨斯大学奥斯汀分校utexas,哈佛大学Harvard,麻省理工学院MIT,田纳西大学UTK,帕森斯设计学院Parsons,佩斯大学Pace,普林斯顿大学Princeton,托莱多大学Toledo,杜克大学Duke,芝加哥大学Chicago,达特茅斯学院Dartmouth,拉文大学La Verne,康奈尔大学Cornell,约翰霍普金斯大学JHU,布朗大学Brown,莱斯大学Rice,埃默里大学Emory,圣母大学,范德堡大学Vandy,加州大学伯克利分校UCB,卡内基梅隆大学CMU,乔治城大学Georgetown,弗吉尼亚大学UVa,塔夫斯大学Tufts,维克森林大学WFU,布兰迪斯大学Brandeis,威廉玛丽学院wm,波士顿学院BC,佐治亚理工学院Gatech,利哈伊大学Lehigh,罗切斯特大学Rochester,威斯康星大学WISC,内布拉斯加大学UNL,伦斯勒理工学院RPI,华盛顿大学UW,加州大学戴维斯分校UCD,加州大学欧文分校UCI,加州大学UCSB,天普大学Temple,叶史瓦大学Yeshiva,肯塔基大学Kentucky,乔治华盛顿大学GWU,雪城大学SU,马里兰大学UMD,佩珀代因大学Pepperdine,乔治亚大学UGA,克莱姆森大学Clemson,福特汉姆大学Fordham,明尼苏达大学UMN,迈阿密大学UM,密西西比大学Mississippi,南卫理公会大学SMU,康涅狄格大学Connecticut,爱荷华大学Iowa,印地安那大学伯明顿分校IUB,特拉华大学UD,伍斯特理工学院WPI,贝勒大学baylor,马凯特大学Marquette,纽约宾汉姆顿大学binghamton,纽约奥尔巴尼大学Albany,克拉克大学Clark,科罗拉多大学CU-Boulder,密苏里大学Missouri,堪萨斯大学KU,北卡罗来纳州立大学NCSU,俄亥俄大学ohio,俄克拉荷马大学Oklahoma,德州A&M大学TAMU,佛罗里达州立大学FSU,斯坦福大学Stanford,加州大学圣地亚哥分校UCSD,凤凰城大学UPX,旧金山大学USF,休斯敦大学UH,斯蒂文斯理工学院SIT,阿拉巴马大学Alabama,塔尔萨大学TU,德雷塞尔大学Drexel,爱荷华州立大学ISU,加州大学河滨分校UCR,丹佛大学DU,堪萨斯州立大学KSU,罗格斯大学Rutgers,佛蒙特大学UVM,奥本大学Auburn,美国东北大学NEU,纽约州立大学石溪分校SBU,亚利桑那州立大学ASU,亚利桑那大学UA,加州大学圣克鲁兹分校UCSC,纽约州立大学布法罗分校Buffalo,纽约理工学院NYIT,北卡罗莱纳大学UNC,罗德岛设计学院RISD,加州旧金山分校UCSF,伊利诺伊大学香槟分校UIUC,杜兰大学Tulane,社区大学College,阿肯色大学,犹他大学,杨百翰大学BYU,辛辛那提大学,霍夫斯特拉大学,肯特州立大学,旧金山艺术大学AAU,莱特州立大学,欧道明大学,罗德岛大学URI,南达科他州立大学,阿肯色大学小石城分校,长岛大学布鲁克林校区,海斯堡州立大学FHSU,圣莫尼卡社区学院SMC,办理美国毕业证文凭学历认证成绩单留学回国证明
 
 
加拿大大学:
多伦多大学,约克大学York,渥太华大学,西安大略大学UWO,滑铁卢大学,麦克马斯特大学McMaster,卡尔顿大学,皇后大学,布鲁克大学,湖首大学,BCIT,温莎大学,瑞尔森大学,百年理工学院,特伦特大学,英属哥伦比亚大学UBC,西蒙菲莎大学SFU,昆特兰理工大学KPU,汤普森河大学TRU,西三一大学,阿尔伯塔大学,卡尔加里大学,里贾纳大学,阿卡迪亚大学,达尔豪斯大学,圣玛丽大学,麦吉尔大学,康考迪亚大学,菲沙河谷大学UFV,蒙特利尔大学,温尼伯大学,曼尼托巴大学,毕业证加拿大文凭学历认证成绩单留学回国证明
未正常毕业*UCLan中央兰开夏大学毕业`等证件`材料证书
作者:qiangpfeg 发表于2016/12/12 20:09:23 原文链接
阅读:15 评论:0 查看评论

未正常毕业*Chester切斯特大学毕业`等证件`材料证书

$
0
0
*切斯特大学毕业证】QQ/微信:549585563  联系人:Kimi 代办国外(海外)澳洲英国 加拿大 韩国 美国 新西兰 等各大学毕业证,修改成绩单分数,学历认证,文凭,diploma,degree
 
 
 
欢迎咨询!QQ/微信:549585563,专业为留学生提供毕业证、学历认证、文凭、学位证、学位证书、使馆公证、国外学历学位教育部认证、使馆留学回国人员证明、录取通知书、Offer、在读证明、雅思托福成绩单、网上存档永久可查!【实体公司,寰宇教育,值得信赖】
  
   一、【主营项目】:
1.毕业证、成绩单、使馆认证、教育部认证、留信、学生卡-- OFFER等.等!
 
2.办理真实使馆公证(即留学回国人员证明,不成功不收费)
 
3.教育部国外学历学位认证咨询。(网上可查、永久存档、快速稳妥)
 
4.办理各国各大学文凭(一对一专业服务,可全程监控跟踪进度)








咨询顾问:Kimi QQ/微信:549585563 
 
1、挂科了,不想读了,成绩不理想怎么办??
2、找工作没有文凭怎么办?有本科却要求硕士又怎么办?
3、打算回国了,找工作的时候,需要提供认证,有文凭却得不到认证。又该怎么办???
 
如果您是以下情况,我们都能竭诚为您解决实际问题:
1、在校期间,因各种原因未能顺利毕业,拿不到官方毕业证; 
2、面对父母的压力,希望尽快拿到;   
3、不清楚流程以及材料该如何准备;   
4、回国时间很长,忘记办;   
5、回国马上就要找工作,办给用人单位看;  
6、企事业单位必须要求办的; 
德国大学:慕尼黑工业大学,哥廷根大学,慕尼黑大学,开姆尼茨工业大学,卡尔斯鲁厄大学,达姆斯塔特工业大学,明斯特大学,弗赖堡大学,多特蒙德工业大学,马堡大学,杜塞尔多夫大学,波鸿鲁尔大学,布伦瑞克工业大学,奥格斯堡大学,杜伊斯堡埃森大学,凯撒斯劳滕工业大学,法兰克福大学,亚琛工业大学,斯图加特大学,汉诺威大学,基尔大学,柏林自由大学,柏林工业大学,吉森大学,纽伦堡大学,莱比锡大学,美因茨大学,乌尔兹堡大学,萨尔大学,科隆大学,不来梅大学,奥登堡大学,安哈尔特应用技术大学,波恩大学,勃兰登堡工业大学,德累斯顿工业大学,汉堡大学,柏林洪堡大学,卡塞尔大学,克劳斯塔尔工业大学,罗斯托克大学,耶拿应用技术大学,汉堡音乐和戏剧学院,鲁昂大学,克莱蒙费朗一大,克莱蒙费朗第二大学,萨瓦大学,佩皮尼昂大学,南布列塔尼大学,巴黎第一大学,第戎大学,国立里昂第二大学,格勒诺布尔第三大学,凡尔赛大学,巴黎第九大学,马赛大学,昂热大学,贝桑松大学,波城大学,滨海大学,科西嘉大学,尼斯大学,巴黎第八大学,南锡一大,雷恩一大,巴黎第四大学,卡昂大学,蒙彼利埃三大,蒙彼利埃第一大学,图尔大学,INSEEC,图卢兹第一大学,图卢兹第三大学,巴黎第四大学索邦大学,斯特拉斯堡大学,图卢兹三大,波尔多一大,里尔第三大学,里昂三大,奥尔良大学,亚眠大学,罗马二大,米兰大学,马兰欧尼,办理德国毕业证文凭学历认证成绩单留学回国证明
 
 
英国大学:
纽卡斯尔大学,帝国理工学院,巴斯大学,埃克塞特大学,伦敦大学学院UCL,华威大学,约克大学,兰卡斯特大学,萨里大学,莱斯特大学,布里斯托大学,伯明翰大学,格鲁斯特大学,谢菲尔德大学,南安普顿大学,拉夫堡大学,爱丁堡大学,诺丁汉大学,伦敦大学亚非学院SOAS,格拉斯哥大学,曼彻斯特大学,伦敦国王学院KCL,皇家霍洛威大学RHUL,阿斯顿大学,利兹大学,萨塞克斯大学,卡迪夫大学,伦敦艺术大学,雷丁大学,肯特大学,利物浦大学,伦敦玛丽女王学院QMUL,赫瑞瓦特大学,埃塞克斯大学,阿伯丁大学,伦敦城市大学,斯特拉思克莱德大学,基尔大学,考文垂大学,斯旺西大学,邓迪大学,阿伯泰大学,切斯特大学,朴茨茅斯大学,威尔士班戈大学,林肯大学,布拉德福德大学,北安普顿大学,诺丁汉特伦特大学,诺森比亚大学,赫尔大学,约克圣约翰大学,哈德斯菲尔德大学,伯恩茅斯大学,伦敦商学院大学,罗汉普顿大学,爱丁堡玛格丽特皇后学院,格林威治大学,赫特福德大学,布鲁内尔大学,德蒙福特大学,罗伯特戈登大学RGU,索尔福德大学,桑德兰大学,威斯敏斯特大学,南岸大学,圣安德鲁斯大学,普利茅斯大学,牛津布鲁克斯大学,伯明翰城市大学BCU,办理英国毕业证文凭学历认证成绩单留学回国证明
 
 
澳洲大学:
梅西大学,林肯大学,奥塔哥大学,奥克兰理工大学AUT,怀卡托大学,基督城理工学院CPIT,马努卡理工学院,坎特伯雷大学,奥克兰大学,奥克兰商学院AIS,悉尼大学USYD,新南威尔士大学UNSW,查尔斯达尔文大学CDU,澳大利亚联邦大学,斯威本科技大学Swinburne,巴拉瑞特大学ballarat,RMIT,墨尔本大学,阿德莱德大学Adelaide,莫纳什大学Monash,昆士兰大学UQ,西澳大学UWA,澳大利亚国立大学ANU,麦考瑞大学Macquarie,纽卡斯尔大学,卧龙岗大学
Wollongong,格里菲斯大学Griffith,弗林德斯大学Flinders,塔斯马尼亚大学UTAS,堪培拉大学,邦德大学Bond,迪肯大学Deakin,悉尼科技大学UTS,科廷大学Curtin,墨尔本皇家理工学院RMIT,昆士兰科技大学QUT,拉筹伯大学La Trobe,莫道克大学Murdoch,澳洲TAFE,南澳大学UniSA,中央昆士兰大学CQU,詹姆斯库克大学JCU,新英格兰大学UNE,南昆士兰大学USQ,埃迪斯科文大学ECU,南十字星大学SCU,阳光海岸大学,维多利亚大学Victoria,办理澳洲毕业证文凭学历认证成绩单留学回国证明
 
 
美国大学:
俄亥俄州立大学OSU,加州大学洛杉矶分校UCLA,华盛顿州立大学WSU,普渡大学Purdue,俄勒冈大学Oregon,纽约大学NYU,西雅图大学Seattle,南加州大学USC,宾州州立大学PSU,匹兹堡大学PITT,加州理工学院CIT,西北大学NWU,
宾夕法尼亚大学Pennsylvania,密歇根州立大学MSU,密歇根大学UMICH,波士顿大学BU,德克萨斯大学奥斯汀分校utexas,哈佛大学Harvard,麻省理工学院MIT,田纳西大学UTK,帕森斯设计学院Parsons,佩斯大学Pace,普林斯顿大学Princeton,托莱多大学Toledo,杜克大学Duke,芝加哥大学Chicago,达特茅斯学院Dartmouth,拉文大学La Verne,康奈尔大学Cornell,约翰霍普金斯大学JHU,布朗大学Brown,莱斯大学Rice,埃默里大学Emory,圣母大学,范德堡大学Vandy,加州大学伯克利分校UCB,卡内基梅隆大学CMU,乔治城大学Georgetown,弗吉尼亚大学UVa,塔夫斯大学Tufts,维克森林大学WFU,布兰迪斯大学Brandeis,威廉玛丽学院wm,波士顿学院BC,佐治亚理工学院Gatech,利哈伊大学Lehigh,罗切斯特大学Rochester,威斯康星大学WISC,内布拉斯加大学UNL,伦斯勒理工学院RPI,华盛顿大学UW,加州大学戴维斯分校UCD,加州大学欧文分校UCI,加州大学UCSB,天普大学Temple,叶史瓦大学Yeshiva,肯塔基大学Kentucky,乔治华盛顿大学GWU,雪城大学SU,马里兰大学UMD,佩珀代因大学Pepperdine,乔治亚大学UGA,克莱姆森大学Clemson,福特汉姆大学Fordham,明尼苏达大学UMN,迈阿密大学UM,密西西比大学Mississippi,南卫理公会大学SMU,康涅狄格大学Connecticut,爱荷华大学Iowa,印地安那大学伯明顿分校IUB,特拉华大学UD,伍斯特理工学院WPI,贝勒大学baylor,马凯特大学Marquette,纽约宾汉姆顿大学binghamton,纽约奥尔巴尼大学Albany,克拉克大学Clark,科罗拉多大学CU-Boulder,密苏里大学Missouri,堪萨斯大学KU,北卡罗来纳州立大学NCSU,俄亥俄大学ohio,俄克拉荷马大学Oklahoma,德州A&M大学TAMU,佛罗里达州立大学FSU,斯坦福大学Stanford,加州大学圣地亚哥分校UCSD,凤凰城大学UPX,旧金山大学USF,休斯敦大学UH,斯蒂文斯理工学院SIT,阿拉巴马大学Alabama,塔尔萨大学TU,德雷塞尔大学Drexel,爱荷华州立大学ISU,加州大学河滨分校UCR,丹佛大学DU,堪萨斯州立大学KSU,罗格斯大学Rutgers,佛蒙特大学UVM,奥本大学Auburn,美国东北大学NEU,纽约州立大学石溪分校SBU,亚利桑那州立大学ASU,亚利桑那大学UA,加州大学圣克鲁兹分校UCSC,纽约州立大学布法罗分校Buffalo,纽约理工学院NYIT,北卡罗莱纳大学UNC,罗德岛设计学院RISD,加州旧金山分校UCSF,伊利诺伊大学香槟分校UIUC,杜兰大学Tulane,社区大学College,阿肯色大学,犹他大学,杨百翰大学BYU,辛辛那提大学,霍夫斯特拉大学,肯特州立大学,旧金山艺术大学AAU,莱特州立大学,欧道明大学,罗德岛大学URI,南达科他州立大学,阿肯色大学小石城分校,长岛大学布鲁克林校区,海斯堡州立大学FHSU,圣莫尼卡社区学院SMC,办理美国毕业证文凭学历认证成绩单留学回国证明
 
 
加拿大大学:
多伦多大学,约克大学York,渥太华大学,西安大略大学UWO,滑铁卢大学,麦克马斯特大学McMaster,卡尔顿大学,皇后大学,布鲁克大学,湖首大学,BCIT,温莎大学,瑞尔森大学,百年理工学院,特伦特大学,英属哥伦比亚大学UBC,西蒙菲莎大学SFU,昆特兰理工大学KPU,汤普森河大学TRU,西三一大学,阿尔伯塔大学,卡尔加里大学,里贾纳大学,阿卡迪亚大学,达尔豪斯大学,圣玛丽大学,麦吉尔大学,康考迪亚大学,菲沙河谷大学UFV,蒙特利尔大学,温尼伯大学,曼尼托巴大学,毕业证加拿大文凭学历认证成绩单留学回国证明
未正常毕业*Chester切斯特大学毕业`等证件`材料证书
作者:qiangpfeg 发表于2016/12/12 20:09:37 原文链接
阅读:13 评论:0 查看评论

未正常毕业*Derby奇切斯特大学毕业`等证件`材料证书

$
0
0
*奇切斯特大学毕业证】QQ/微信:549585563  联系人:Kimi 代办国外(海外)澳洲英国 加拿大 韩国 美国 新西兰 等各大学毕业证,修改成绩单分数,学历认证,文凭,diploma,degree
 
 
 
欢迎咨询!QQ/微信:549585563,专业为留学生提供毕业证、学历认证、文凭、学位证、学位证书、使馆公证、国外学历学位教育部认证、使馆留学回国人员证明、录取通知书、Offer、在读证明、雅思托福成绩单、网上存档永久可查!【实体公司,寰宇教育,值得信赖】
  
   一、【主营项目】:
1.毕业证、成绩单、使馆认证、教育部认证、留信、学生卡-- OFFER等.等!
 
2.办理真实使馆公证(即留学回国人员证明,不成功不收费)
 
3.教育部国外学历学位认证咨询。(网上可查、永久存档、快速稳妥)
 
4.办理各国各大学文凭(一对一专业服务,可全程监控跟踪进度)








咨询顾问:Kimi QQ/微信:549585563 
 
1、挂科了,不想读了,成绩不理想怎么办??
2、找工作没有文凭怎么办?有本科却要求硕士又怎么办?
3、打算回国了,找工作的时候,需要提供认证,有文凭却得不到认证。又该怎么办???
 
如果您是以下情况,我们都能竭诚为您解决实际问题:
1、在校期间,因各种原因未能顺利毕业,拿不到官方毕业证; 
2、面对父母的压力,希望尽快拿到;   
3、不清楚流程以及材料该如何准备;   
4、回国时间很长,忘记办;   
5、回国马上就要找工作,办给用人单位看;  
6、企事业单位必须要求办的; 
德国大学:慕尼黑工业大学,哥廷根大学,慕尼黑大学,开姆尼茨工业大学,卡尔斯鲁厄大学,达姆斯塔特工业大学,明斯特大学,弗赖堡大学,多特蒙德工业大学,马堡大学,杜塞尔多夫大学,波鸿鲁尔大学,布伦瑞克工业大学,奥格斯堡大学,杜伊斯堡埃森大学,凯撒斯劳滕工业大学,法兰克福大学,亚琛工业大学,斯图加特大学,汉诺威大学,基尔大学,柏林自由大学,柏林工业大学,吉森大学,纽伦堡大学,莱比锡大学,美因茨大学,乌尔兹堡大学,萨尔大学,科隆大学,不来梅大学,奥登堡大学,安哈尔特应用技术大学,波恩大学,勃兰登堡工业大学,德累斯顿工业大学,汉堡大学,柏林洪堡大学,卡塞尔大学,克劳斯塔尔工业大学,罗斯托克大学,耶拿应用技术大学,汉堡音乐和戏剧学院,鲁昂大学,克莱蒙费朗一大,克莱蒙费朗第二大学,萨瓦大学,佩皮尼昂大学,南布列塔尼大学,巴黎第一大学,第戎大学,国立里昂第二大学,格勒诺布尔第三大学,凡尔赛大学,巴黎第九大学,马赛大学,昂热大学,贝桑松大学,波城大学,滨海大学,科西嘉大学,尼斯大学,巴黎第八大学,南锡一大,雷恩一大,巴黎第四大学,卡昂大学,蒙彼利埃三大,蒙彼利埃第一大学,图尔大学,INSEEC,图卢兹第一大学,图卢兹第三大学,巴黎第四大学索邦大学,斯特拉斯堡大学,图卢兹三大,波尔多一大,里尔第三大学,里昂三大,奥尔良大学,亚眠大学,罗马二大,米兰大学,马兰欧尼,办理德国毕业证文凭学历认证成绩单留学回国证明
 
 
英国大学:
纽卡斯尔大学,帝国理工学院,巴斯大学,埃克塞特大学,伦敦大学学院UCL,华威大学,约克大学,兰卡斯特大学,萨里大学,莱斯特大学,布里斯托大学,伯明翰大学,格鲁斯特大学,谢菲尔德大学,南安普顿大学,拉夫堡大学,爱丁堡大学,诺丁汉大学,伦敦大学亚非学院SOAS,格拉斯哥大学,曼彻斯特大学,伦敦国王学院KCL,皇家霍洛威大学RHUL,阿斯顿大学,利兹大学,萨塞克斯大学,卡迪夫大学,伦敦艺术大学,雷丁大学,肯特大学,利物浦大学,伦敦玛丽女王学院QMUL,赫瑞瓦特大学,埃塞克斯大学,阿伯丁大学,伦敦城市大学,斯特拉思克莱德大学,基尔大学,考文垂大学,斯旺西大学,邓迪大学,阿伯泰大学,切斯特大学,朴茨茅斯大学,威尔士班戈大学,林肯大学,布拉德福德大学,北安普顿大学,诺丁汉特伦特大学,诺森比亚大学,赫尔大学,约克圣约翰大学,哈德斯菲尔德大学,伯恩茅斯大学,伦敦商学院大学,罗汉普顿大学,爱丁堡玛格丽特皇后学院,格林威治大学,赫特福德大学,布鲁内尔大学,德蒙福特大学,罗伯特戈登大学RGU,索尔福德大学,桑德兰大学,威斯敏斯特大学,南岸大学,圣安德鲁斯大学,普利茅斯大学,牛津布鲁克斯大学,伯明翰城市大学BCU,办理英国毕业证文凭学历认证成绩单留学回国证明
 
 
澳洲大学:
梅西大学,林肯大学,奥塔哥大学,奥克兰理工大学AUT,怀卡托大学,基督城理工学院CPIT,马努卡理工学院,坎特伯雷大学,奥克兰大学,奥克兰商学院AIS,悉尼大学USYD,新南威尔士大学UNSW,查尔斯达尔文大学CDU,澳大利亚联邦大学,斯威本科技大学Swinburne,巴拉瑞特大学ballarat,RMIT,墨尔本大学,阿德莱德大学Adelaide,莫纳什大学Monash,昆士兰大学UQ,西澳大学UWA,澳大利亚国立大学ANU,麦考瑞大学Macquarie,纽卡斯尔大学,卧龙岗大学
Wollongong,格里菲斯大学Griffith,弗林德斯大学Flinders,塔斯马尼亚大学UTAS,堪培拉大学,邦德大学Bond,迪肯大学Deakin,悉尼科技大学UTS,科廷大学Curtin,墨尔本皇家理工学院RMIT,昆士兰科技大学QUT,拉筹伯大学La Trobe,莫道克大学Murdoch,澳洲TAFE,南澳大学UniSA,中央昆士兰大学CQU,詹姆斯库克大学JCU,新英格兰大学UNE,南昆士兰大学USQ,埃迪斯科文大学ECU,南十字星大学SCU,阳光海岸大学,维多利亚大学Victoria,办理澳洲毕业证文凭学历认证成绩单留学回国证明
 
 
美国大学:
俄亥俄州立大学OSU,加州大学洛杉矶分校UCLA,华盛顿州立大学WSU,普渡大学Purdue,俄勒冈大学Oregon,纽约大学NYU,西雅图大学Seattle,南加州大学USC,宾州州立大学PSU,匹兹堡大学PITT,加州理工学院CIT,西北大学NWU,
宾夕法尼亚大学Pennsylvania,密歇根州立大学MSU,密歇根大学UMICH,波士顿大学BU,德克萨斯大学奥斯汀分校utexas,哈佛大学Harvard,麻省理工学院MIT,田纳西大学UTK,帕森斯设计学院Parsons,佩斯大学Pace,普林斯顿大学Princeton,托莱多大学Toledo,杜克大学Duke,芝加哥大学Chicago,达特茅斯学院Dartmouth,拉文大学La Verne,康奈尔大学Cornell,约翰霍普金斯大学JHU,布朗大学Brown,莱斯大学Rice,埃默里大学Emory,圣母大学,范德堡大学Vandy,加州大学伯克利分校UCB,卡内基梅隆大学CMU,乔治城大学Georgetown,弗吉尼亚大学UVa,塔夫斯大学Tufts,维克森林大学WFU,布兰迪斯大学Brandeis,威廉玛丽学院wm,波士顿学院BC,佐治亚理工学院Gatech,利哈伊大学Lehigh,罗切斯特大学Rochester,威斯康星大学WISC,内布拉斯加大学UNL,伦斯勒理工学院RPI,华盛顿大学UW,加州大学戴维斯分校UCD,加州大学欧文分校UCI,加州大学UCSB,天普大学Temple,叶史瓦大学Yeshiva,肯塔基大学Kentucky,乔治华盛顿大学GWU,雪城大学SU,马里兰大学UMD,佩珀代因大学Pepperdine,乔治亚大学UGA,克莱姆森大学Clemson,福特汉姆大学Fordham,明尼苏达大学UMN,迈阿密大学UM,密西西比大学Mississippi,南卫理公会大学SMU,康涅狄格大学Connecticut,爱荷华大学Iowa,印地安那大学伯明顿分校IUB,特拉华大学UD,伍斯特理工学院WPI,贝勒大学baylor,马凯特大学Marquette,纽约宾汉姆顿大学binghamton,纽约奥尔巴尼大学Albany,克拉克大学Clark,科罗拉多大学CU-Boulder,密苏里大学Missouri,堪萨斯大学KU,北卡罗来纳州立大学NCSU,俄亥俄大学ohio,俄克拉荷马大学Oklahoma,德州A&M大学TAMU,佛罗里达州立大学FSU,斯坦福大学Stanford,加州大学圣地亚哥分校UCSD,凤凰城大学UPX,旧金山大学USF,休斯敦大学UH,斯蒂文斯理工学院SIT,阿拉巴马大学Alabama,塔尔萨大学TU,德雷塞尔大学Drexel,爱荷华州立大学ISU,加州大学河滨分校UCR,丹佛大学DU,堪萨斯州立大学KSU,罗格斯大学Rutgers,佛蒙特大学UVM,奥本大学Auburn,美国东北大学NEU,纽约州立大学石溪分校SBU,亚利桑那州立大学ASU,亚利桑那大学UA,加州大学圣克鲁兹分校UCSC,纽约州立大学布法罗分校Buffalo,纽约理工学院NYIT,北卡罗莱纳大学UNC,罗德岛设计学院RISD,加州旧金山分校UCSF,伊利诺伊大学香槟分校UIUC,杜兰大学Tulane,社区大学College,阿肯色大学,犹他大学,杨百翰大学BYU,辛辛那提大学,霍夫斯特拉大学,肯特州立大学,旧金山艺术大学AAU,莱特州立大学,欧道明大学,罗德岛大学URI,南达科他州立大学,阿肯色大学小石城分校,长岛大学布鲁克林校区,海斯堡州立大学FHSU,圣莫尼卡社区学院SMC,办理美国毕业证文凭学历认证成绩单留学回国证明
 
 
加拿大大学:
多伦多大学,约克大学York,渥太华大学,西安大略大学UWO,滑铁卢大学,麦克马斯特大学McMaster,卡尔顿大学,皇后大学,布鲁克大学,湖首大学,BCIT,温莎大学,瑞尔森大学,百年理工学院,特伦特大学,英属哥伦比亚大学UBC,西蒙菲莎大学SFU,昆特兰理工大学KPU,汤普森河大学TRU,西三一大学,阿尔伯塔大学,卡尔加里大学,里贾纳大学,阿卡迪亚大学,达尔豪斯大学,圣玛丽大学,麦吉尔大学,康考迪亚大学,菲沙河谷大学UFV,蒙特利尔大学,温尼伯大学,曼尼托巴大学,毕业证加拿大文凭学历认证成绩单留学回国证明
未正常毕业*Derby奇切斯特大学毕业`等证件`材料证书
作者:qiangpfeg 发表于2016/12/12 20:09:59 原文链接
阅读:12 评论:0 查看评论

综合算法05—考虑换乘的K短路算法

$
0
0

一、问题描述

在路网中,已知站点、线路和线路-站点数据,有条件:
1、考虑到换乘时要花费一定的时间,因此对换乘路径费用要加上换乘时间。
2、当路网复杂时,为了避免多余计算,定义有效路径,使得路径在有效路径范围内。有效路径为最短路径的(1+h)倍。
求满足条件的K短路。

二、算法描述

1.K短路算法:

Step1:令k=1,求出最短路,并加上t换乘;

Step2:k=k+1,求出k短路,并加上t换乘;

Step3:判断,if是有效路径,保存并转Step2;else转Step4;

Step4:删除路径,结束。


2.换乘时间算法(假设换乘时间基于换乘次数):

if 路径所有站点都在线路j上,n=0;

else if 存在i站点,使得起点到i的所有站点都在线路j1上,i到终点的所有站点都在j2上,则n=1;

else if 存在i1、i2,使得起点到i1的所有站点都在线路j1上,i1到i2间所有站点都在j2上,i2到终点的所有站点都在j3上,则n=2;

else n=∞;

t换乘=n*换乘一次的平均时间。

三、算法程序

使用说明:将以下代码分别保存为m文件放在同一个目录下,注意名称不能错,修改案例请打开luwangshuju.m,运行程序请打开huanchengsuanfa.m。
1.fuhaoshuoming.m
fprintf('======================================================================\n');
fprintf('                   《换乘方案算法——不对方案排序》\n');
fprintf('运行环境:MATLAB 8.3.0.532 \n');
fprintf('作者信息:兰州交通大学  刘志祥   QQ:531548824\n');
fprintf('说明:本程序用于在已知路网数据时,通过输入起讫点求直达、一次、二次换乘方案。\n')
fprintf('======================================================================\n\n');
%% 符号体系
%% 路网数据符号
%==============================================================================
% luwangshuju-路网数据,包括站数据(点编号),线数据(线编号),站—线数据(站与线的0-1矩阵,表示站是否在线上),线-站数据(线与站的0-1矩阵,表示线是否包含站),路权数据(如行驶时间或距离)。
% A-起点
% B-终点
% zhan-站集合,本程序中站点以V开头编号
% xian-线集合,可理解为公交车名称,如k102等
% zhan_xian-线与站的关系,表示线路上有哪些站点
%==============================================================================


%% 数据处理符号
%==============================================================================
% zhan_xian_01-线与站的01矩阵,行表示线,列表示站,0表示不在该线,1表示在该线上
% xian_zhan_01-站与线的01矩阵,行表示站,列表示线,0表示线不经过站,1表示经过,与zhan_xian_01互为转置矩阵
%==============================================================================


%% 换乘次数符号
%==============================================================================
% KHc_cishu-换乘次数
% KHc_hcd-换乘点
% KHc_hcqj-换乘区间
% KHc_hcld_a-换乘路段
%==============================================================================


%% K短路算法符号
%==============================================================================
% KPaths-有效路径
% KCosts-有效路径的费用(本文指时间)
%==============================================================================

%% 其他符号见程序内注释

2.luwangshuju.m
%=============================================================================
% 路网数据
% 运行可得基础路网数据
% 主要计算结果:【输入起讫点 得到路网的站-线-权数据 】
%=============================================================================
%% 输入始发点和目的地
% O=input('O=');
% D=input('D=');
O=2;
D=9;
%=============================================================================


%% 数据for K短路算法
%=============================================================================
% 例1
% Road_Net =[
%     0     3    2     Inf   Inf   Inf   Inf   Inf   Inf
%     3     0    Inf   1    3     Inf   Inf   Inf   2
%     2      Inf  0     Inf   2     Inf   Inf   Inf   Inf
%     Inf    1    Inf   0     Inf   3     Inf   Inf   Inf
%     Inf    3    2     Inf   0    4    3     Inf   Inf
%     Inf    Inf  Inf   3    4    0     Inf   Inf   Inf
%     Inf    Inf  Inf   Inf   3     Inf   0    2     Inf
%     Inf    Inf  Inf   Inf   Inf   Inf   2    0     Inf
%     Inf    2    Inf   Inf   Inf   Inf   Inf   Inf   0];
% zhan=[1 2 3 4 5 6 7 8 9];                                                   %站数据
% xian=[1 2 3 4 5 6];                                                       %线路数据
% xian_zhan={[1 2 4 6],[1 3 5 7 8],[9 2 5 6],[6 4 2 1],[8 7 5 3 1],[6 5 2 9]};%线路包含哪些站
% ============================================================================


% 例2
%=============================================================================
Road_Net =[
     0     2   Inf     3   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf
     2     0     4   Inf     4   Inf   Inf   Inf   Inf   Inf   Inf     3   Inf
   Inf     4     0   Inf   Inf     3   Inf   Inf   Inf   Inf   Inf   Inf   Inf
     3   Inf   Inf     0     8   Inf     2   Inf   Inf     4   Inf   Inf   Inf
   Inf     4   Inf     8     0     9   Inf     2   Inf   Inf   Inf   Inf   Inf
   Inf   Inf     3   Inf     9     0   Inf   Inf     4   Inf     5   Inf   Inf
   Inf   Inf   Inf     2   Inf   Inf     0     3   Inf   Inf   Inf   Inf   Inf
   Inf   Inf   Inf   Inf     2   Inf     3     0     6   Inf   Inf   Inf     3
   Inf   Inf   Inf   Inf   Inf     4   Inf     6     0   Inf   Inf   Inf   Inf
   Inf   Inf   Inf     4   Inf   Inf   Inf   Inf   Inf     0   Inf   Inf   Inf
   Inf   Inf   Inf   Inf   Inf     5   Inf   Inf   Inf   Inf     0   Inf   Inf
   Inf     2   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf   Inf     0   Inf
   Inf   Inf   Inf   Inf   Inf   Inf   Inf     3   Inf   Inf   Inf   Inf     0];
zhan=[1 2 3 4 5 6 7 8 9 10 11 12 13];                                       %站数据
xian=[1 2 3 4 5 6];                                                   %线路数据
xian_zhan={[1 2 3 6 9 8 7 4],[10 4 5 6 11],[12 2 5 8 13],[4 7 8 9 6 3 2 1],...
    [11 6 5 4 10],[13 8 5 2 12]};                                         %线路包含哪些站,注意要和roadnet对应起来,如果线路的始发站和终点站直接相连,即为环线。
%=============================================================================
Cost_of_Transfer=2.5;
H=1;
a=0;
Kmax=inf;
%=============================================================================


3.shujuchuli.m
%=============================================================================
% 数据处理
% 运算依赖于luwangshuju.m
% 主要运算结果【得到普通线站关系的01矩阵】...
%=============================================================================

%以下代码用于换乘算法
%% 线_站单元数组转换为01矩阵
%=============================================================================
xian_zhan_01=zeros(length(xian),length(zhan));
for i=1:length(xian)
    xian_zhan_01(i,xian_zhan{i})=1;
end
zhan_xian_01=xian_zhan_01';
%=============================================================================


%以下代码用于K短路算法
%% 根据路网对路段进行自动标号并求出每个路段的距离
%=============================================================================
for i=1:length(Road_Net)
    for j=1:length(Road_Net)
        if Road_Net(i,j)~=0&Road_Net(i,j)~=inf
            a=a+1;
            luduan_zhan{a}={i,j};
            W_luduan{a}=Road_Net(i,j);
        end
    end
end
%=============================================================================


%以下代码用于FrankWolfe算法
%% 根据路段标号和路线-节点关系,求出路线-路段的0-1矩阵
%=============================================================================
luxian_luduan_01mat=zeros(length(xian_zhan),length(luduan_zhan));           %线路-路径0-1矩阵,表示某线路是否包含该路段
m=1;
while m<=length(xian_zhan)
    for i=2:length(xian_zhan{m})
        for k=1:length(luduan_zhan)
            if isequal(cell2mat(luduan_zhan{k}),xian_zhan{m}([i-1 i]))
                luxian_luduan_01mat(m,k)=1;
            end
        end
    end
    m=m+1;
end
%=============================================================================


%% 路线-节点改为路线-路段
%=============================================================================
for i=1:length(xian_zhan)
    a=0;
    for j=2:length(xian_zhan{i})
        for k=1:length(luduan_zhan)
            if xian_zhan{i}([j-1,j])==cell2mat(luduan_zhan{k})
                a=a+1;
                luxian_luduan{i}(a)=k;
                W_luxian_luduan{i}(a)=W_luduan(k);
            end
        end
    end
end
%=============================================================================

4.huanchengcishu.m



%% ===========================================================================
% 换乘次数
% 被KSP.m调用才可计算
% 主要运算结果【换乘次数、换乘点、换乘区间、换乘路段】
%=============================================================================
KHc_hcd{k}=[];
KHc_hcqj{k}=[];
KHc_hcld_a{k}=[];

%% 直达线路
%=============================================================================
KHc_cishu=length(luduan_zhan);                              %最大换乘次数
m1=1;
m2=length(KPaths{k});
for j1=1:length(xian_zhan)
    if all(ismember(KPaths{k}(m1:m2),xian_zhan{j1}))
        if find(O==xian_zhan{j1})<find(D==xian_zhan{j1})
            KHc_cishu=0;
            KHc_hcd{k}={[]};
            KHc_hcqj{k}={[]};
            KHc_hcld_a{k}={[]};
        end
    end
end
%=============================================================================

%% 一次换乘
%=============================================================================
for i=2:length(KPaths{k})-1
    for j1=1:length(xian_zhan)
        for j2=1:length(xian_zhan)
            if KHc_cishu~=0
                if all(ismember(KPaths{k}(1:i),xian_zhan{j1})) & all(ismember(KPaths{k}(i:length(KPaths{k})),xian_zhan{j2}))& j1~=j2
                    if find(O==xian_zhan{j1})<find(KPaths{k}(i)==xian_zhan{j1})& find(D==xian_zhan{j2})>find(KPaths{k}(i)==xian_zhan{j1})
                        KHc_cishu=1;
                        KHc_hcd{k}={KPaths{k}(i)};
                        KHc_hcqj{k}={[KPaths{k}(i) KPaths{k}(i+1)]};
                        for a=1:length(luduan_zhan)
                            if [KPaths{k}(i) KPaths{k}(i+1)]==cell2mat(luduan_zhan{a})
                                KHc_hcld_a{k}={a};
                            end
                        end
                    end
                end
            end
        end
    end
end
%=============================================================================

%% 二次换乘
%=============================================================================
for i1=2:length(KPaths{k})-1
    for i2=i1:length(KPaths{k})-1
        for j1=1:length(xian_zhan)
            for j2=1:length(xian_zhan)
                for j3=1:length(xian_zhan)
                    if KHc_cishu~=0&KHc_cishu~=1
                        if all(ismember(KPaths{k}(1:i1),xian_zhan{j1})) & all(ismember(KPaths{k}(i1:i2),xian_zhan{j2}))& all(ismember(KPaths{k}(i2:length(KPaths{k})),xian_zhan{j3}))
                            if j1~=j2 &j2~=j3 &j1~=j3&KPaths{k}(i1)~=KPaths{k}(i2)
                                if(find(O==xian_zhan{j1})<find(KPaths{k}(i1)==xian_zhan{j1}))  & find(KPaths{k}(i1)==xian_zhan{j2})<find(KPaths{k}(i2)==xian_zhan{j2}) &  find(D==xian_zhan{j3})>find(KPaths{k}(i2)==xian_zhan{j3})
                                    KHc_cishu=2;
                                    KHc_hcd{k}={KPaths{k}(i1) KPaths{k}(i2)};
                                    KHc_hcqj{k}={[KPaths{k}(i1) KPaths{k}(i1+1)];[KPaths{k}(i2) KPaths{k}(i2+1)]};
                                    for a1=1:length(luduan_zhan)
                                        for a2=1:length(luduan_zhan)
                                            if [KPaths{k}(i1) KPaths{k}(i1+1)]==cell2mat(luduan_zhan{a1})&[KPaths{k}(i2) KPaths{k}(i2+1)]==cell2mat(luduan_zhan{a2})
                                                KHc_hcld_a{k}={a1 a2};
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
    end
end
%=============================================================================

5.dijkstra.m
function [shortestPath, totalCost] = dijkstra(netCostMatrix, s, d)
n = size(netCostMatrix,1);
for i = 1:n
    farthestPrevHop(i) = i; 
    farthestNextHop(i) = i;
end
visited(1:n) = false;
distance(1:n) = inf;    
parent(1:n) = 0;
distance(s) = 0;
for i = 1:(n-1),
    temp = [];
    for h = 1:n,
        if ~visited(h)  
            temp=[temp distance(h)];
        else
            temp=[temp inf];
        end
    end;
    [t, u] = min(temp);     
    visited(u) = true;         
    for v = 1:n,  
        if ( ( netCostMatrix(u, v) + distance(u)) < distance(v) )
            distance(v) = distance(u) + netCostMatrix(u, v); 
            parent(v) = u;  
        end;
    end;
end;

shortestPath = [];
if parent(d) ~= 0 
    t = d;
    shortestPath = [d];
    while t ~= s
        p = parent(t);
        shortestPath = [p shortestPath];        
        if netCostMatrix(t, farthestPrevHop(t)) < netCostMatrix(t, p)
            farthestPrevHop(t) = p;
        end;
        if netCostMatrix(p, farthestNextHop(p)) < netCostMatrix(p, t)
            farthestNextHop(p) = t;
        end;        
        t = p;
    end;
end;
totalCost = distance(d);

6.KSP.m
clear
clc
%==========================================================================
% K短路算法+换乘算法
% 运算调用huanchengcishu.m
% 主要运算结果【KPaths KCosts Mxf】
%==========================================================================

%% 1. 输入并处理相关的路网数据
%==========================================================================
luwangshuju;
shujuchuli;
k=1;
n=0;
%==========================================================================

%% 2. K短路算和换乘算法结合,求出有效路径
%==========================================================================
if ismember([O D],zhan) & O~=D
    %% 2.1 调用Dijkstra算法求出最短路路径及费用
    [path costs]=dijkstra(Road_Net, O, D);
    if isempty(path)
        KPaths=[];
        KCosts=[];
    else
        %% 2.2 初始化
        path_number = 1;                %路径从1开始编号
        P{path_number,1}= path;         %单元数组P第一行表示路径
        P{path_number,2}= costs;        %单元数组P第二行表示路径阻抗
        current_P = path_number;
        size_X=1;
        X{size_X}={path_number; path; costs};%1-编号,2-路径,3-阻抗值
        S(path_number)= path(1);        %路径的开始站点
        KPaths{k}= path;
        KCosts{k}= costs;
        
        %% 2.3 调用换乘次数函数
        while (k<Kmax && size_X ~=0)
            huanchengcishu;                                %求出路径k的换乘次数
            KHc_n{k}=KHc_cishu;
            KCosts{k}=KCosts{k}+KHc_cishu*Cost_of_Transfer;%求出考虑换乘后的总费用
            costs=min(cell2mat(KCosts));                   %更新最小费用

            %% 2.4 删除非有效路径
            if  KCosts{k}>(H+1)*costs
                k=k-1;
                KCosts=KCosts(1:k);
                KPaths=KPaths(1:k);
                KHc_n=KHc_n(1:k);
                KHc_hcd=KHc_hcd(1:k);
                KHc_hcqj=KHc_hcqj(1:k);
                KHc_hcld_a=KHc_hcld_a(1:k);
                break
            end
            %% 2.5 关闭已搜索的路径
            for i=1:length(X)
                if  X{i}{1}== current_P
                    size_X = size_X - 1;
                    X(i)=[];
                    break;
                end
            end
            P_= P{current_P,1};
            w = S(current_P);
            for i=1:length(P_)
                if w==P_(i)
                    w_index_in_path=i;                           %找到w在路径中的位置
                end
            end
            %% 2.6 更新路网矩阵
            for index_dev_vertex= w_index_in_path:length(P_)- 1
                temp_luwangjuzhen = Road_Net;
                for i = 1: index_dev_vertex-1
                    v = P_(i);
                    temp_luwangjuzhen(v,:)=inf;
                    temp_luwangjuzhen(:,v)=inf;
                end
                SP_sameSubPath=[];
                index =1;
                SP_sameSubPath{index}=P_;
                for i=1:length(KPaths)
                    if length(KPaths{i})>= index_dev_vertex     %如果路径长度大于index_dev_vertex,即还没有完成搜索
                        if P_(1:index_dev_vertex)== KPaths{i}(1:index_dev_vertex)   %对比当前路径和K路径的前index_dev_vertex个点,如果匹配,继续对比,否则为不匹配
                            index = index+1;                    %匹配成功则自动进入下一个节点对比
                            SP_sameSubPath{index}=KPaths{i};
                        end
                    end
                end
                v_ = P_(index_dev_vertex);
                for j = 1: length(SP_sameSubPath)
                    next=SP_sameSubPath{j}(index_dev_vertex+1);
                    temp_luwangjuzhen(v_,next)=inf;
                end
                sub_P=P_(1:index_dev_vertex);
                costs_sub_P=0;
                for i=1:length(sub_P)-1
                    costs_sub_P=costs_sub_P+Road_Net(sub_P(i),sub_P(i+1));
                end
                [dev_p c]= dijkstra(temp_luwangjuzhen, P_(index_dev_vertex), D);
                if ~isempty(dev_p)
                    path_number=path_number+1;
                    P{path_number,1}=[sub_P(1:end-1) dev_p];     %连接起点到终点的路径
                    P{path_number,2}= costs_sub_P + c ;          %计算子路径及偏差定点到终点费用的和(最终费用)
                    S(path_number)= P_(index_dev_vertex);
                    size_X = size_X + 1;
                    X{size_X}={path_number; P{path_number,1};P{path_number,2}};
                    %                                             更新当前数据(路径编号,路径,路径费用)
                end
            end
            %% 2.7 防错处理,如果指定路径数目大于路网穷举数目,防错,否则最后的结果会发生重复,也可能进入死循环。
            if size_X > 0
                shortestXCosts= X{1}{3};                         %路径费用
                shortestX= X{1}{1};                              %判定路径
                for i=2:size_X
                    if  X{i}{3}< shortestXCosts
                        shortestX= X{i}{1};
                        shortestXCosts= X{i}{3};
                    end
                end
                current_P=shortestX;
                k=k+1;
                KPaths{k}= P{current_P,1};
                KCosts{k}= P{current_P,2};
            else
                k=k+1;
            end
        end
    end
else
    warning('起点或终点不在指定路网中!按任意键请重新输入。。。');
    pause
    KSP
end
%==========================================================================
%% 3.有效路径
%% 3.1 保留有效路径并排序
%==========================================================================
KCosts=cell2mat(KCosts);
yxlj=find(KCosts<min(KCosts)*(1+H));
KCosts=KCosts(yxlj);
[KCosts,yxlj]=sort(KCosts);
KPaths=KPaths(yxlj);
KHc_n=KHc_n(yxlj);
KHc_hcd=KHc_hcd(yxlj);
KHc_hcqj=KHc_hcqj(yxlj);
KHc_hcld_a=KHc_hcld_a(yxlj);
%==========================================================================

%% 3.2 根据有效路径求得路径-路段的01矩阵
%==========================================================================
Mxf=zeros(length(KPaths),length(luduan_zhan));
m=1;
while m<=length(KPaths)
    for i=2:length(KPaths{m})
        for k=1:length(luduan_zhan)
            if isequal(cell2mat(luduan_zhan{k}),KPaths{m}([i-1 i]))
                Mxf(m,k)=1;
            end
        end
    end
    m=m+1;
end
%==========================================================================

%% 3.3 有效路径路径-换乘路段的01矩阵
%==========================================================================
if ~isempty(KHc_hcld_a)
    M=zeros(size(Mxf));
    for k=1:length(KPaths)
        M(k,[cell2mat(KHc_hcld_a{k})])=Cost_of_Transfer;
    end
end
%==========================================================================

%% 4. 主要计算结果
%==========================================================================
KPaths             %有效路径
KCosts             %有效路径的费用(本文指时间)
KHc_n              %换乘次数
KHc_hcd=KHc_hcd    %换乘点
KHc_hcqj=KHc_hcqj  %换乘区间
KHc_hcld_a         %换乘路段
%==========================================================================

四、算例及运行结果

1.算例1

路网如图1所示,已知站数据、线数据及站-线数据。给定起点v4,终点v8。求路径方案。


1.1 运行结果

修改luwangshuju.m——qidian=4;zhongdian=8;

>> KSP

KPaths = 

    [1x5 double]    [1x7 double]    [1x5 double]


KCosts =

   14.0000   15.5000   17.0000


KHc_n = 

    [2]    [1]    [2]


KHc_hcd = 

    {1x2 cell}    {1x1 cell}    {1x2 cell}


KHc_hcqj = 

    {2x1 cell}    {1x1 cell}    {2x1 cell}


KHc_hcld_a = 

    {1x2 cell}    {1x1 cell}    {1x2 cell}
1.2 数据查看
KPaths{:}

ans =

     4     2     5     7     8


ans =

     4     2     1     3     5     7     8


ans =

     4     6     5     7     8
KHc_hcd{:}


ans = 


    [2]    [5]


ans = 


    [1]


ans = 


    [6]    [5]
KHc_hcqj{1}{:}


ans =
     2     5

ans =
     5     7
KHc_hcqj{2}{:}

ans =
     1     3
KHc_hcqj{3}{:}

ans =
     6     5

ans =
     5     7
KHc_hcld_a{:}

ans = 

    [5]    [14]

ans = 

    [2]

ans = 

    [16]    [14]

说明:v4到v8有3条有效路径,排序后为KPaths,费用为KCosts,换乘次数分别为KHc_n,换乘区间为KHc_hcqj(换乘区间是换乘点到其紧后节点),换乘路段为KHc_hcld_a。

编号 KPaths KCosts KHc_n KHc_hcqj KHc_hcld_a
k1 4->2->5->7->8 14 2 [2,5] [5,7] [5] [14]
k2 4->2->1->3->5->7->8 15.5 1 [1,3] [2]
k3 4->6->5->7->8 17 2 [6,5] [5,7] [16] [14]

2.算例2
路网如图2所示,已知站数据、线数据及站-线数据。给定起点v2,终点v9。求路径方案。

图2  某简单路网结构图

2.1 运行结果

修改luwangshuju.m——qidian=2;zhongdian=9;

>> KSP

KPaths = 

    [1x4 double]    [1x4 double]    [1x6 double]


KCosts =

   11.0000   14.5000   16.0000


KHc_n = 

    [0]    [1]    [0]


KHc_hcd = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}


KHc_hcqj = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}


KHc_hcld_a = 

    {1x1 cell}    {1x1 cell}    {1x1 cell}
2.2 数据查看

>> KPaths{:}

ans =

     2     3     6     9


ans =

     2     5     8     9


ans =

     2     1     4     7     8     9
>> KHc_hcd{:}

ans = 

    {[]}


ans = 

    [8]


ans = 

    {[]}
KHc_hcqj{1}{:} ={[]}
KHc_hcqj{2}{:}={[ 8     9]}
KHc_hcqj{3}{:} ={[]}
>> KHc_hcld_a{:}

ans = 

    {[]}


ans = 

    [25]


ans = 

    {[]}

说明:v2到v9有3条有效路径,排序后为KPaths,费用为KCosts,换乘次数分别为KHc_n,换乘区间为KHc_hcqj,换乘路段为KHc_hcld_a。

编号 KPaths KCosts KHc_n KHc_hcqj KHc_hcld_a
k1 2->3->6->9 11 0 [] []
k2 2->5->8->9 14.5 1 [8,9] [25]
k3 2->1->4->7->8->9 16 0 [] []

五、结论及展望

在路网站点、线路、站点-线路关系已知时,通过输入起讫点可以计算出路径及其换乘次数。考虑换乘费用和有效路径后,路径数量大大减少,而过滤掉的路径为多余路径,在实际走行中不必考虑。该算法将在多领域得到应用,例如流量分配方面。

六、代码下载

代码下载地址:


作者:LZX19901012 发表于2016/12/12 20:12:19 原文链接
阅读:17 评论:0 查看评论

poj2965——The Pilots Brothers' refrigerator(模拟)

$
0
0

Description

The game “The Pilots Brothers: following the stripy elephant” has a quest where a player needs to open a refrigerator.

There are 16 handles on the refrigerator door. Every handle can be in one of two states: open or closed. The refrigerator is open only when all handles are open. The handles are represented as a matrix 4х4. You can change the state of a handle in any location [i, j] (1 ≤ i, j ≤ 4). However, this also changes states of all handles in row i and all handles in column j.

The task is to determine the minimum number of handle switching necessary to open the refrigerator.

Input

The input contains four lines. Each of the four lines contains four characters describing the initial state of appropriate handles. A symbol “+” means that the handle is in closed state, whereas the symbol “−” means “open”. At least one of the handles is initially closed.

Output

The first line of the input contains N – the minimum number of switching. The rest N lines describe switching sequence. Each of the lines contains a row number and a column number of the matrix separated by one or more spaces. If there are several solutions, you may give any one of them.

Sample Input

-+–


-+–
Sample Output

6
1 1
1 3
1 4
4 1
4 3
4 4

给出4x4的把手,每次转动一个把手,其所在的列和行的把手都会被转动,求最少需要转动的把手至所有把手都打开,+号表示这个把手是关的
最主要的还是找规律吧,分享一个高效率的算法http://www.myexception.cn/other/1801786.html

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cstdio>
#include <set>
#include <cmath>
#include <map>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAXN 100010
#define Mod 10001
using namespace std;
int a[10][10];
int main()
{
    char x;
    memset(a,0,sizeof(a));
    for(int i=1;i<=4;++i)
    {
        for(int j=1;j<=4;++j)
        {
            cin>>x;
            if(x=='+')
            {
                for(int k=1;k<=4;++k)
                {
                    a[i][k]++;
                    a[k][j]++;
                }
                a[i][j]--;
            }
        }
    }
    int ans=0;
    for(int i=1;i<=4;++i)
        for(int j=1;j<=4;++j)
            if(a[i][j]%2)
                ans++;
    printf("%d\n",ans);
    for(int i=1;i<=4;++i)
        for(int j=1;j<=4;++j)
            if(a[i][j]%2)
                printf("%d %d\n",i,j);
    return 0;
}
作者:blue_skyrim 发表于2016/12/12 20:23:28 原文链接
阅读:13 评论:0 查看评论

Linux的scp命令

$
0
0

文章作者:Tyan
博客:noahsnail.com  |  CSDN  |  简书

Linux系统下访问服务器经常会碰到需要将服务器的文件拷贝到本地机器的问题,Linux系统中存在一个跨机器拷贝的命令scp。scp是secure copy的简写,用于在Linux下进行远程文件拷贝,scp是跨服务器的并且传输是加密的。scp命令使用主要有两种形式:

  • 将文件从服务器拷贝到本地,在本地执行scp命令
# 命令形式:scp remote_server_address local_dir_file

# Demo,将服务器的/home/test/目录下的filename文件拷贝到本机的当前目录下
$ scp server_ip:/home/test/filename ./
  • 将文件从本地上传到服务器上,在本地执行scp命令
# 命令形式:scp local_dir_file remote_server_address

# Demo,将当前目录下的filename文件上传到服务器的/home/test目录下
$ scp ./filename server_ip:/home/test
filename              100% 6419KB   3.1MB/s   00:02 

**备注:**scp命令还有一些参数用来控制文件的上传下载,参数如下:

  • -1 强制scp命令使用协议ssh1
  • -2 强制scp命令使用协议ssh2
  • -4 强制scp命令只使用IPv4寻址
  • -6 强制scp命令只使用IPv6寻址
  • -B 使用批处理模式(传输过程中不询问传输口令或短语)
  • -C 允许压缩。
  • -p 保留原文件的修改时间,访问时间和访问权限。
  • -q 不显示传输进度条。
  • -r 递归复制整个目录。
  • -v 详细方式显示输出。
  • -c cipher 以cipher将数据传输进行加密,这个选项将直接传递给ssh。
  • -F ssh_config 指定一个替代的ssh配置文件,此参数直接传递给ssh。
  • -i identity_file 从指定文件中读取传输时使用的密钥文件,此参数直接传递给ssh。
  • -l limit 限定用户所能使用的带宽,以Kbit/s为单位。
  • -P port port是指定数据传输使用的端口号
  • -S program 指定加密传输时所使用的程序。
作者:Quincuntial 发表于2016/12/12 20:24:27 原文链接
阅读:14 评论:0 查看评论

ecFun——JavaEE综合实战项目

$
0
0

这个网站是我们四个人一起写的大作业,得了95分,被设计报告毁了,故在这里修改后补上,各位可以用来学习使用,源码可直接导入使用:点我获取源码

ecFun漫画音乐综合娱乐网站设计报告

一. 网站介绍

目前我国纯娱乐性质的网站太少,到后来网站都逐渐商业化,以获取更多利润,而反观当下,人们生活节奏逐渐加快,背负的压力越来越大,于是很多青少年走上游戏的不归路,更有甚者,许多人压力无处释放,赌博,吸毒泛滥成灾。当前放松性质的网站做的较有名气的也就是开心网,但近些年来已被人们遗忘,如今也是无人经营,广告遍布。于是,我们便打算做出一个完全供人们放松的网站,只希望用户从中获得快乐。

ecFun名称的由来便是Economic(电子的)comedy (喜剧,幽默) Fun(有趣),我们愿意专心为您创造快乐。

二. 功能

    总体来讲,ecFun是综合娱乐类的网站,任意人均可看漫画,听音乐,读笑话。但只有注册登陆后的用户才可以上传自己喜欢的漫画,音乐,笑话,或进入聊天室与别人聊天。用户若是同别人分享漫画音乐和笑话后,会获取积分值,每发布一帖积分增加一,若是发布不良信息则会被管理员删除,并扣除10点积分,当积分小于0时,无法登录,永久封号,这样保证了网站的健康。

三. 构架

  本网站使用MVC的设计模式,网站整体分为三层,Model,View,Controller。HTML5 , CSS3 , JQuery,Javascript设计前端,使用JSP动态网页技术搭建后台,使用hibernate框架操作mysql实现数据的持久化,JSON和Ajax异步网页加载技术实现了聊天室内容时时更新的功能。

四. 页面组织

该网站分为首页和趣漫画,音乐,文章,社区聊天室4个子页面,首页和子页面采取统一模版,导航栏,登录面板和侧栏样式相同,网站整体页面风格一致。

五.数据库设计

使用了mysql数据库,先建一个greathomework数据库,在此数据库里建五张表

 

user存储用户信息,cartoon存储漫画信息,joke存储笑话信息,music存储音乐信息,chat存储聊天信息。

六.JSP设计

AudioPlayer里的cartoon.jsp用来显示漫画的界面的,music.jsp是来显示音乐的界面的,showpdf.jsp是用来处理pdf类型的漫画,chat.jsp用来显示聊天页面,deliver.jsp是用户发送音乐,漫画与笑话的页面,joke.jsp是用户显示笑话的页面,main.jsp是主页面,login.jsp是登录页面,register.jsp是注册页面,manage.jsp是管理员管理网站,删除帖子的页面。

七.如何使用源码。

需要准备的开发环境,推荐myeclipse10.0及以上,mysql5.5及以上,tomcat7.x及以上,jdk7.x及以上,navicat。

首先在mysql里建立一个greathomework的数据库,然后选定greathomework数据库,右键执行sql文件,并选择store.sql,然后将源代码导入myeclipse中,将此代码发布到tomcat服务器上,用浏览器访问http://localhost:8080/GreatHomeWork/main.jsp开始您的探索。

作者:qq_33665647 发表于2016/12/12 20:42:23 原文链接
阅读:19 评论:0 查看评论

poj2506——Tiling(递推+大数加)

$
0
0

Description

In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles?
Here is a sample tiling of a 2x17 rectangle.
这里写图片描述

Input

Input is a sequence of lines, each line containing an integer number 0 <= n <= 250.
Output

For each line of input, output one integer number in a separate line giving the number of possible tilings of a 2xn rectangle.
Sample Input

2
8
12
100
200
Sample Output

3
171
2731
845100400152152934331135470251
1071292029505993517027974728227441735014801995855195223534251

给2x1和2x2的地板,求铺成2xn的面积有多少种排列方式
网上找的,都是大神,真的。说什么a[n]=a[n-1]+2*a[n-2],反正我是没看出来

#include<cstdio>
#include<string>
#include<iostream>
using namespace std;
string a[300];
string Add(string s1,string s2)
{
    if (s1.length()<s2.length())
        swap(s1,s2);
    int i,j;
    for(i=s1.length()-1,j=s2.length()-1;i>=0;i--,j--)
    {
        s1[i]=s1[i]+(j>=0?s2[j]-'0':0);
        if(s1[i]-'0'>=10)
        {
            s1[i]=(s1[i]-'0')%10+'0';
            if(i) s1[i-1]++;
            else s1='1'+s1;
        }
    }
    return s1;
}
int main()
{
    int i,n;
    a[0]="1",a[1]="1",a[2]="3";
    for (i=3; i<=250; i++)
        a[i]=Add(Add(a[i-1],a[i-2]),a[i-2]);
    while (cin>>n)
       cout<<a[n]<<endl;
    return 0;
}
作者:blue_skyrim 发表于2016/12/12 20:52:15 原文链接
阅读:10 评论:0 查看评论

空间配置器(二)

$
0
0
提前声明:这个文章本来应该命名为空间配置器(一)的,也就是说,这篇文章应该诞生于上篇文章 之前的,然而,由于本人的原因,造成这样的失误。

最近一直在读《STL源码剖析》的第2章节,在讲述空间配置器的外部接口的时候,并不是特别清楚,反倒是把两级空间配置器的底层实现细节搞得比较清晰,所以,上一篇文章先于本篇文章。这两天,仔细阅读了接口这一部分,然后加上对自己空间配置器的使用,决定再来整理此文。
1.空间配置器的外部接口:
在上一篇文章中,我们知道,大于128字节的,就调用一级空间配置器,小于128字节的就调用二级空间配置器,

整个设计究竟只开放一级空间配置器还是同时开放二级空间配置器,取决于__USE_MALLOC是否被定义,如果定义了,就调用一级空间配置器,如果没有定义,就调用二级空间配置器(中间有可能去调到一级空间配置器)。SGI STL并未定义__USE_MALLOC。(引至《STL源码剖析》侯捷著)

所以,无论如何,中间都有可能去调到malloc()函数。
也就是说,默认调用二级空间配置器,如果大于128字节,才去调用一级空间配置器。
下边给出一级空间配置器和二级空间配置器的外部包装接口:(注明:截取至《STL源码剖析》侯捷著)

这样对两级空间配置器的外部接口也是比较清楚了。
我们需要在Alloc.h的文件中补充外部接口:
#ifdef __USE_MALLOC
    typedef __MallocAllocTemplate<0> Alloc;
#else
    typedef __DefaultAllocTemplate<false,0> Alloc;
#endif//__USE_MALLOC
template<typename T,typename _Alloc = Alloc>
class SimpleAlloc
{
public:
    static T* Allocate(size_t n)
    {
       return (T*)(_Alloc::Allocate(n * sizeof(T)));
    }
    static T* Allocate()
    {
       return (T*)(_Alloc::Allocate(sizeof(T)));
    }
    static void Deallocate(T* ptr,size_t n)
    {
       _Alloc::Deallocate(ptr,n * sizeof(T));
    }
    static void Deallocate(T* ptr)
    {
       _Alloc::Deallocate(ptr,sizeof(T));
    }
};
2.空间配置器的使用
在上篇文章,我们使用trace跟踪来测试空间配置器的,这里,我们自己模拟实现一个容器list,然后使用自己的空间配置器。
//list.h文件
#pragma once
#include"Alloc.h"
#include"Construct.h"
template<typename T>
struct ListNode
{
    T _data;
    ListNode<T>* _prev;
    ListNode<T>* _next;
    ListNode(const T& x = T())
       :_data(x)
       ,_prev(NULL)
       ,_next(NULL)
    {}
};
template<typename T,typename Ref,typename Ptr>
struct ListIterator
{
    typedef ListIterator<T,T&,T*> Self;
    typedef ListNode<T> Node;
    Node* _node;
    ListIterator(Node* p)
       :_node(p)
    {}
    Self& operator++()
    {
       _node = _node->_next;
       return *this;
    }
    Self operator++(int)
    {
       Node* tmp = _node;
       _node = _node->_next;
       return tmp;
    }
    Self& operator--()
    {
       _node = _node->_prev;
       return *this;
    }
    Self operator--(int)
    {
       Node* tmp = _node;
       _node = _node->_prev;
       return tmp;
    }
    Ref operator*()
    {
       return _node->_data;
    }
    Ptr operator->()
    {
       return &(operator*());
    }
    bool operator != (const Self& s) const
    {
       return _node != s._node;
    }
    bool operator == (const Self& s) const
    {
       return !(*this != s);
    }
};
template<typename T,typename  _Alloc = Alloc>
class List
{
    typedef ListNode<T> Node;
    typedef SimpleAlloc<Node, _Alloc> ListNodeAllocator;
public:
    typedef ListIterator<T,T&,T*> Iterator;
    typedef ListIterator<T,const T&,const T*> ConstIterator;
    List()
       :_head(NULL)
    {
       _head = BuyNode(T());
       _head->_next = _head;
       _head->_prev = _head;
    }
    ~List()
    {
       Clear();
       DestroyNode(_head);
    }
    void Clear()
    {
       Iterator it = Begin();
       while(it != End())
       {
           Node* del = it._node;
           ++it;
           DestroyNode(del);
       }
       _head->_prev = _head;
       _head->_next = _head;
    }
    void Insert(Iterator pos,const T& x)
    {
       Node* cur = pos._node;
       Node* prev = cur->_prev;
       Node* tmp = BuyNode(x);
       tmp->_next = cur;
       prev->_next = tmp;
       tmp->_prev = prev;
       cur->_prev = tmp;
    }
    void Erase(Iterator pos)
    {
       Node* del = pos._node;
       Node* prev = del->_prev;
       Node* next = del->_next;
       prev->_next = next;
       next->_prev = prev;
       
    }
    Iterator Begin()
    {
       return _head->_next;
    }
    ConstIterator Begin() const
    {
       return _head->_next;
    }
    Iterator End()
    {
       return _head;
    }
    ConstIterator End() const
    {
       return _head;
    }
    void PushBack(const T& x)
    {
       Insert(Iterator(_head),x);
    }
protected:
    Node* BuyNode(const T& x)
    {
       Node* node = ListNodeAllocator::Allocate();
       Construct(node,x);
       return node;
    }
    void DestroyNode(Node* ptr)
    {
       Destory(ptr);
       ListNodeAllocator::Deallocate(ptr);
    }
private:
    Node* _head;
};
//construct.h文件
#pragma once
template<class T1, class T2>
inline void Construct(T1* p, T2 value)
{
    new(p) T1(value);
}
template<class T>
inline void Destory(T* p)
{
    p->~T();
}



作者:peiyao456 发表于2016/12/12 21:01:45 原文链接
阅读:0 评论:0 查看评论

【HIbernate框架学习】:Hibernate对象继承关系映射(一)

$
0
0

       继承关系映射实现的三种策略:

       单表继承:每棵类继承树使用一个表(table per class hierarchy) ,也就是一棵继承树映射一张表。

       具体表继承:每个子类一个表(table per subclass),也就是每个子类各自映射表。

       类表继承:每个具体类一个表(table per concrete class)(有一些限制),也就是继承树的每个类各自映射表,除非将父类定义成抽象的,否则父类也是一张表。

       每个类继承树对应一张表

       因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪

个类的。这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。

       用hibernate实现这种策略的时候,有如下步骤:

       父类用普通的<class>标签定义;

       在父类中定义一个discriminator,即指定这个区分的字段的名称和类型

如:<discriminator column=”XXX” type=”string”/>;

       子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:

       subclass标签的name属性是子类的全路径名;

       在subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)

的值;
       subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平

行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的

全路径名称。

       子类的其它属性,像普通类一样,定义在subclass标签的内部;

       Hibernate会自动存储鉴别值,在加载的时候会根据鉴别值取得相关的对象;

       我们来看例子,这个类继承树的类图以及数据表:

       

       具体的代码:

       Animal实体类:

package com.demo.domain;

public class Animal {

	private int id;
	private String name;
	private boolean sex;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public boolean isSex() {
		return sex;
	}

	public void setSex(boolean sex) {
		this.sex = sex;
	}
	
}

       Pig实体类:

package com.demo.domain;

public class Pig extends Animal {

	private int weight;

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}
	
}

       Bird实体类:

package com.demo.domain;

public class Bird extends Animal {

	private int height;

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}
	
}

       对象关系映射文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.demo.domain">
	<class name="Animal" table="t_animal" lazy="false">
		<id name="id">
			<generator class="native"/>
		</id>
		
		<discriminator column="type" type="string"/>
		
		<property name="name"/>
		<property name="sex"/>
		
		<subclass name="Pig" discriminator-value="P">
			<property name="weight"/>
		</subclass>
		
		<subclass name="Bird" discriminator-value="B">
			<property name="height"/>
		</subclass>
		
	</class>
</hibernate-mapping>

       测试类:

package com.demo.test;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;

import com.demo.domain.Animal;
import com.demo.domain.Bird;
import com.demo.domain.HibernateUtils;
import com.demo.domain.Pig;

import junit.framework.TestCase;

public class ExtendsTest extends TestCase {

	public void testSave1() {
		Session session = null;
		
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Pig pig = new Pig();
			pig.setName("小猪猪");
			pig.setSex(true);
			pig.setWeight(200);
			session.save(pig);
			
			Bird bird = new Bird();
			bird.setName("小鸟鸟");
			bird.setSex(false);
			bird.setHeight(100);
			session.save(bird);
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 采用load查询,通过Pig查询
	 */
	public void testLoad1() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Pig pig = (Pig)session.load(Pig.class, 1);
			System.out.println(pig.getName());
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	

	/**
	 * 采用load查询,通过Animal查询
	 */
	public void testLoad2() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Animal a = (Animal)session.load(Animal.class, 1);
			System.out.println(a.getName());
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 采用load查询,通过Animal查询
	 */
	public void testLoad3() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Animal a = (Animal)session.load(Animal.class, 1);
			//因为load默认支持lazy,所以我们看到的是Animal的代理
			//所以采用instanceof无法鉴别出真正的类型Pig
			//所load在此情况下是不支持多态查询的
			//多态查询:hibernate在加载数据的时候,能够采用instancof鉴别出其真正的类型
			if (a instanceof Pig) {
				System.out.println(a.getName());
			}else {
				System.out.println("不是猪!");
			}
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}		
	
	/**
	 * 采用load查询,通过Animal查询
	 * 将<class>标签中的lazy设置为false
	 */
	public void testLoad4() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Animal a = (Animal)session.load(Animal.class, 1);
			//可以正确判断出其真正的类型
			//因为映射文件中lazy设置为false,返回的不再是代理类而是真正的类型
			//所以可以鉴别出来
			//此种情况下load是支持多态查询的
			if (a instanceof Pig) {
				System.out.println(a.getName());
			}else {
				System.out.println("不是猪!");
			}
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}		
	
	/**
	 * 采用get查询,通过Animal查询
	 */
	public void testLoad5() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			Animal a = (Animal)session.get(Animal.class, 1);
			//可以鉴别出其真正的类型,因为get返回的就是具体类
			//get是支持多态查询的
			if (a instanceof Pig) {
				System.out.println(a.getName());
			}else {
				System.out.println("不是猪!");
			}
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 采用hql查询Animal
	 */
	@SuppressWarnings("unchecked")
	public void testLoad6() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			List<Animal> animalList = session.createQuery("from Animal").list();
			for (Iterator<Animal> iter=animalList.iterator(); iter.hasNext();) {
				Animal a = (Animal)iter.next();
				//采用hql查询返回的是真正的类型,所以hql支持多态查询
				if (a instanceof Pig) {
					System.out.println(a.getName());
				}else if (a instanceof Bird) {
					System.out.println(a.getName());
				}
			}
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
	/**
	 * 采用hql查询Animal
	 */
	@SuppressWarnings("rawtypes")
	public void testLoad7() {
		Session session = null;
		try {
			session = HibernateUtils.getSession();
			session.beginTransaction();
			
			List list = session.createQuery("from java.lang.Object").list();
			for (Iterator iter=list.iterator(); iter.hasNext();) {
				Object o = iter.next();
				if (o instanceof Pig) {
					System.out.println(o);
				}else if (o instanceof Bird) {
					System.out.println(o);
				}
			}
			
			session.getTransaction().commit();
		}catch(Exception e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally {
			HibernateUtils.closeSession(session);
		}
	}	
	
}

       testSave1()方法:

       控制台输出:

       

       数据库显示:

       

       testLoad1()方法:

       控制台输出:

       

       testLoad2()方法:

       控制台输出:

       

       testLoad3()方法:

       控制台输出:

       

       testLoad4()方法:

       控制台输出: 

       

       testLoad5()方法:

       控制台输出:

       

       testLoad6()方法:

       控制台输出:

       

       testLoad7()方法:

       控制台输出:

       

        

       多态查询:Hibernate在加载数据的时候,能够采用instancof鉴别出其真正的类型。get和hql支持多态查询;

load在lazy设置为false的情况下支持多态查询。




作者:erlian1992 发表于2016/12/12 21:06:34 原文链接
阅读:0 评论:0 查看评论

【机器视觉】 单目视觉测距

$
0
0

http://blog.csdn.net/purgle/article/details/50811490


 

单目视觉测距

 1800人阅读 评论(0) 收藏 举报
 分类:

1、引言

近年来,由于无人机、无人车等技术的不断成熟,需要用到实时测距的场所也越来越多,如定位,避障,测速等,相比于其他测距方法,单目测距是利用一个摄像头进行视频拍摄,在图像中找到待测物体。这一系列动作,涉及到了物体的识别,相机的结构,坐标变换的一些知识,距离的获取是一个很广泛的课题,用摄像头来测距是其中一个方向,包括单目测距、双目测距、结构光测距等方法。

在这里,我们主要用一个摄像头通过建立一定的模型来解决测距的问题。

 

2、摄相机模型:

单目摄像头的模型可以近似考虑为针孔模型,如图所示:

 

                                                         图1. 摄相机针孔成像模型     来自Forsyth

 

f为摄像头的焦距

c为镜头光心

物体发出的光经过相机的光心,然后成像于图像传感器或者也可以说是像平面上,如果设物体所在平面与相机平面的距离为d,物体实际高度为H,在传感器上的高度为h,那么有这样的关系:

                                                                                        

我们接下依据的也主要是这条公式,那么根据这个思路,我们主要的难点是物体在传感器上的高度 怎么测量,一旦 是足够精确的,那么所测的距离 的精确度也能够得到保证。

下面来主要推导h应该怎么来求。

 

 

 

3、单目视觉测距原理

接下来就是本文的主要部分,主要介绍物体投影在传感器上的高度 怎么获得。

由公式①可知,这里的关键点在于怎么确定物体在图像上的高度,在这之前,我们唯一能够做到的就是识别出某个具体的物体,但前提是已知其实际高度H,先谈谈我们怎样简单地识别出一个物体的:物体的识别必须围绕其特征做文章,实验时,我们暂时挑一个简单易识别的东西来,如图所示,我们识别对象是一张粉红色的凳子:

 

                                                                                                                             

                                                                                                                    图2. 被测量的实际对象


                                                                                                                     

                                                                                                                       图3. 识别后的图形

现在我们基于如下假设,一步步完善我们的测距模型:

假设一:物体中心在主光轴上,且镜头平面与物体所在平面平行,可以用下图表示:

                                                              

                                                                                                                                           图4. 假设一模型图

 

由我们前面所述的摄像头模型中,可以清楚地知道,图像传感器是接受光线的关键器件,如果我们想要求出物像实际高度,从传感器尺寸出发,举个例子,我们用到的摄像头传感器尺寸是1/2.7英尺,换算成米制单位之后,传感器的宽度为SENSOR_WIDTH= 5.31mm,高度为SENSOR_HEIGHT = 3.98mm,设物体的像素高度为Taget_h,则:

                                                                 

结合①②两条公式,就能计算假设一模型的距离了。

假设二:物体偏离光轴夹角 α ,镜头平面仍与物体平面平行,如图:

                                                                                                                                    

5. 假设二模型图

同样跟据假设一的解决方法,因为光心穿过图像的中心(图中的(Cx,Cy)就是图像中心),那么物体与图像中心的距离为:

  

则角度α 为:                                  

在假设二的情况下,结合①②③④,可以求出具体的距离。

 

 

 

 

4、摄相机畸变及其解决

这里简单地介绍畸变现象,由于我们平常使用的摄像头焦距小,可以当成一个凸透镜,那么光线通过不同厚度的镜片时,光线发生弯折的情况也不一样,这被称为径向畸变,对于径向畸变来说,远离透镜中心的光线弯曲比靠近中心的严重的多,这对我们依靠像素点来求物体的物像高度是不利的。除了径向畸变外,还有一个很重要的的切向畸变,而这由整个摄像机的组装过程中出现的问题引起,如透镜本身与图像平面不平行产生切向畸变。
畸变的产生涉及到了一些复杂的几何光学的知识,而这两种图像畸变是我们误差的主要来源,那么应该怎么去解决这种畸变呢?
解决畸变的问题必须回到摄像机拍摄视频的本质上来,摄像头本质上是把实际三维空间坐标投影到图像平面上,成为一个二维平面图, 可以用如下式子表示:

                                                                                         

上面的Q称为重投影矩阵,它由摄像头的内参数矩阵和外参数矩阵所决定,(xy)是图像上的点的坐标,而(XYZ)是实际物理空间坐标。

也就是说假如我们知道足够多的三维空间与图像二维平面上的一一对应关系,那么通过上面的约束关系,就可以将未知的参数求出来。具体的方法分为两步,求摄像机内参数和外参数,这里直接用matlabCalibrate ToolBox很容易就可以得到内参数和外参数,这里就不再赘述了。 

                                                                             参考资料:Gary Bradski&Adrian Kaebler. Learning OpenCV



作者:Taily_Duan 发表于2016/12/13 11:27:56 原文链接
阅读:12 评论:0 查看评论

Android MVP 详解(下)如有侵权告知删除谢谢

$
0
0

Android MVP 详解(下)

5. 最佳实践

好了终于要点讲自己的东西了,有点小激动。下面这些仅表示个人观点,非一定之规,各位看官按需取用,有说的不对的,敬请谅解。关于命名规范可以参考我的另一篇文章“Android 编码规范”。老规矩先上图:


MVPBestPractice 思维导图


在参考了 kenjuwagatsuma 的 MVP Architecture in Android Development 和 Saúl Molinero的 A useful stack on android #1, architecture 之后,我决定采用如下的分层方案来构建这个演示Demo,如下:


分层架构方案


总体架构可以被分成四个部分 :
Presentation:负责展示图形界面,并填充数据,该层囊括了 View 和 Presenter (上图所示的Model我理解为 ViewModel -- 为 View 提供数据的 Model,或称之为 VO -- View Object)。
Domain:负责实现app的业务逻辑,该层中由普通的Java对象组成,一般包括 Usecases 和 Business Logic。
Data:负责提供数据,这里采用了 Repository 模式,Repository 是仓库管理员,Domain 需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。Android 开发中常见的数据来源有,RestAPI、SQLite数据库、本地缓存等。
Library:负责提供各种工具和管理第三方库,现在的开发一般离不开第三方库(当然可以自己实现,但是不要重复造轮子不是吗?),这里建议在统一的地方管理(那就是建一个单独的 module),尽量保证和 Presentation 层分开。


AndroidStudio 中构建项目

5.1. 关于包结构划分

一个项目是否好扩展,灵活性是否够高,包结构的划分方式占了很大比重。很多项目里面喜欢采用按照特性分包(就是Activity、Service等都分别放到一个包下),在模块较少、页面不多的时候这没有任何问题;但是对于模块较多,团队合作开发的项目中,这样做会很不方便。所以,我的建议是按照模块划分包结构。其实这里主要是针对 Presentation 层了,这个演示 Demo 我打算分为四个模块:登录,首页,查询天气和我的(这里仅仅是为了演示需要,具体如何划分模块还得根据具体的项目,具体情况具体分析了)。划分好包之后如下图所示:


包结构划分

5.2. 关于res拆分

功能越来越多,项目越做越大,导致资源文件越来越多,虽然通过命名可以对其有效归类(如:通过添加模块名前缀),但文件多了终究不方便。得益于 Gradle,我们也可以对 res 目录进行拆分,先来看看拆分后的效果:


按模块拆分 res 目录


注意:resource 目录的命名纯粹是个人的命名偏好,该目录的作用是用来存放那些不需要分模块放置的资源。
res 目录的拆分步骤如下:
1) 首先打开 module 的 build.gradle 文件


res 拆分 Step1


2) 定位到 defaultConfig {} 与 buildTypes {} 之间


res 拆分 Step2.png


3) 在第二步定位处编辑输入 sourceSets {} 内容,具体内容如下:

sourceSets {
    main {
        manifest.srcFile 'src/main/AndroidManifest.xml'
        java.srcDirs = ['src/main/java','.apt_generated']
        aidl.srcDirs = ['src/main/aidl','.apt_generated']
        assets.srcDirs = ['src/main/assets']
        res.srcDirs =
        [
                'src/main/res/home',
                'src/main/res/login',
                'src/main/res/mine',
                'src/main/res/weather',
                'src/main/res/resource',
                'src/main/res/'

        ]
    }
}

4) 在 res 目录下按照 sourceSets 中的配置建立相应的文件夹,将原来 res 下的所有文件(夹)都移动到 resource 目录下,并在各模块中建立 layout 等文件夹,并移入相应资源,最后 Sync Project 即可。

5.3. 怎么写 Model

这里的 Model 其实贯穿了我们项目中的三个层,Presentation、Domain 和 Data。暂且称之为 Model 吧,这也我将提供 Repository 功能的层称之为 Data Layer 的缘故(有些称这一层为 Model Layer)。

首先,谈谈我对于 Model 是怎么理解的。应用都离不开数据,而这些数据来源有很多,如网络、SQLite、文件等等。一个应用对于数据的操作无非就是:获取数据、编辑(修改)数据、提交数据、展示数据这么几类。从分层的思想和 JavaEE 开发中积累的经验来看,我觉得 Model 中的类需要分类。从功能上来划分,可以分出这么几类:
VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
DTO(Data Transfer Object):数据传输对象,这个概念来源于 JavaEE 的设计模式,原来的目的是为了 EJB 的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。
DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。
PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应 PO 的一个(或若干个)属性。

注意:关于vo、dto、do、po可以参考这篇文章-“领域驱动设计系列文章——浅析VO、DTO、DO、PO的概念、区别和用处

当然这些不一定都存在,这里只是列举一下,可以有这么多分类,当然列举的也不全。

其次,要搞清楚 Domain 层和 Data 层分别是用来做什么的,然后才知道哪些 Model 该往 Data 层中写,哪些该往 Domain 层中写。
Data 层负责提供数据。
Data 层不会知道任何关于 Domain 和 Presentation 的数据。它可以用来实现和数据源(数据库,REST API或者其他源)的连接或者接口。这个层面同时也实现了整个app所需要的实体类。
Domain 层相对于 Presentation 层完全独立,它会实现应用的业务逻辑,并提供 Usecases。
Presentation 从 Domain 层获取到的数据,我的理解就是 VO 了,VO 应该可以直接使用。

注意:这里说的直接使用是指不需要经过各种转换,各种判断了,如 Activity 中某个控件的显示隐藏是根据 VO 中的 visibility 字段来决定,那么这个最好将 visibility 作为 int 型,而且,取值为VISIBLE/INVISIBLE/GONE,或者至少是 boolean 型的。

注意:这里所谓的业务逻辑可能会于 Presenter 的功能概念上有点混淆。打个比方,假如 usecase 接收到的是一个 json 串,里面包含电影的列表,那么把这个 json 串转换成 json 以及包装成一个 ArrayList,这个应当是由 usecase 来完成。而假如 ArrayList 的 size 为0,即列表为空,需要显示缺省图,这个判断和控制应当是由 Presenter 完成的。(上述观点参考自:Saúl Molinero

最后,就是关于 Data 层,采用的 Repository 模式,建议抽象出接口来,Domain 层需要感知数据是从哪里取出来的。

5.4. 怎么写 View

先区分一下Android View、View、界面的区别
Android View: 指的是继承自android.view.View的Android组件。
View:接口和实现类,接口部分用于由 Presenter 向 View 实现类通信,可以在 Android 组件中实现它。一般最好直接使用 Activity,Fragment 或自定义 View。
界面:界面是面向用户的概念。比如要在手机上进行界面间切换时,我们在代码中可以通过多种方式实现,如 Activity 到 Activity 或一个 Activity 内部的 Fragment/View 进行切换。所以这个概念基于用户的视觉,包括了所有 View 中能看到的东西。

那么该怎么写 View 呢?

在 MVP 中 View 是很薄的一层,里面不应该有业务逻辑,所以一般只提供一些 getter 和 setter 方法,供 Presenter 操作。关于 View,我有如下建议:

  1. 简单的页面中直接使用 Activity/Fragment 作为 View 的实现类,然后抽取相应的接口
  2. 在一些有 Tab 的页面中,可以使用 Activity + Fragment ( + ViewPager) 的方式来实现,至于 ViewPager,视具体情况而定,当然也可以直接 Activity + ViewPager 或者其他的组合方式
  3. 在一些包含很多控件的复杂页面中,那么建议将界面拆分,抽取自定义 View,也就是一个 Activity/Fragment 包含多个 View(实现多个 View 接口)

5.5. 怎么写 Presenter

Presenter 是 Android MVP 实现中争论的焦点,上篇中介绍了多种“MVP 框架”,其实都是围绕着Presenter应该怎么写。有一篇专门介绍如何设计 Presenter 的文章(Modeling my presentation layer),个人感觉写得不错,这里借鉴了里面不少的观点,感兴趣的童鞋可以去看看。下面进入正题。
为什么写 Presenter 会这么纠结,我认为主要有以下几个问题:

  1. 我们将 Activity/Fragment 视为 View,那么 View 层的编写是简单了,但是这有一个问题,当手机的状态发生改变时(比如旋转手机)我们应该如何处理Presenter对象,那也就是说 Presenter 也存在生命周期,并且还要“手动维护”(别急,这是引起来的,下面会细说)
  2. Presenter 中应该没有 Android Framework 的代码,也就是不需要导 Framework 中的包,那么问题来了,页面跳转,显示对话框这些情况在 Presenter 中该如何完成
  3. 上面说 View 的时候提到复杂的页面建议通过抽取自定义 View 的方式,将页面拆分,那么这个时候要怎么建立对应的 Presenter 呢
  4. View 接口是可以有多个实现的,那我们的 Presenter 该怎么写呢

好,现在我将针对上面这些问题一一给出建议。

5.5.1. 关于 Presenter 生命周期的问题

先看图(更详细讲解可以看看这篇文章Presenter surviving orientation changes with Loaders


Presenter生命周期


如上图所示,方案1和方案2都不够优雅(这也是很多“MVP 框架”采用的实现方案),而且并不完善,只适用于一些场景。而方案3,让人耳目一新,看了之后不禁想说 Loader 就是为 Presenter 准备的啊。这里我们抓住几个关键点就好了:

  • Loader 是 Android 框架中提供的
  • Loader 在手机状态改变时是不会被销毁
  • Loader 的生命周期是是由系统控制的,会在Activity/Fragment不再被使用后由系统回收
  • Loader 与 Activity/Fragment 的生命周期绑定,所以事件会自己分发
  • 每一个 Activity/Fragment 持有自己的 Loader 对象的引用
  • 具体怎么用,在 Antonio Gutierrez 的文章已经阐述的很明白,我就不再赘述了

好吧,我有一点要补充,上面说的方案1和方案2不是说就没有用了,还是视具体情况而定,如果没有那么多复杂的场景,那么用更简单的方案也未尝不可。能解决问题就好,不要拘泥于这些条条框框...(话说,咱这不是为了追求完美吗,哈哈)

5.5.2. 关于页面跳转和显示Dialog

首先说说页面跳转,前一阵子忙着重构公司的项目,发现项目中很多地方使用 startActivity() 和使用 Intent 的 putExtra() 显得很乱;更重要的是从 Intent 中取数据的时候需要格外小心——类型要对应,key 要写对,不然轻则取不到数据,重则 Crash。还有一点,就是当前 Activity/Fragment 必须要知道目标 Activity 的类名,这里耦合的很严重,有没有。当时就在想这是不是应该封装一下啊,或者有更好的解决方案。于是,先在网上搜了一下,知乎上有类似的提问,有人建议写一个 Activity Router(Activity 路由表)。嗯,正好和我的思路类似,那就开干。

我的思路很简单,在 util 包中定义一个 NavigationManager 类,在该类中按照模块使用注释先分好区块(为什么要分区块,去看看我的 “Android 编码规范”)。然后为每个模块中的 Activity 该如何跳转,定义一个静态方法。

如果不需要传递数据的,那就很简单了,只要传入调用者的 Context,直接 new 出 Intent,调用该 Context 的 startActivity() 方法即可。代码如下:


导航管理类-跳转系统页面

导航管理类-跳转不需要传递数据的页面

如果需要传递数据呢?刚才说了,使用 Bundle 或者 putExtra() 这种方式很不优雅,而且容易出错(那好,你个给优雅的来看看,哈哈)。确实,我没想到比较优雅的方案,在这里我提供一个粗糙的方案,仅供大家参考一下,如有你有更好的,那麻烦也和我分享下。

我的方案是这样的,使用序列化对象来传递数据(建议使用 Parcelable,不要偷懒去用 Serializable,这个你懂的)。为需要传递数据的 Activity 新建一个实现了 Parcelable 接口的类,将要传递的字段都定义在该类中。其他页面需要跳转到该 Activity,那么就需要提供这个对象。在目标 Activity 中获取到该对象后,那就方便了,不需要去找对应的 key 来取数据了,反正只要对象中有的,你就能直接使用。

注意:这里我建议将序列化对象中的所有成员变量都定义为 public 的,一来,可以减少代码量,主要是为了减少方法数(虽说现在对于方法数超 64K 有比较成熟的 dex 分包方案,但是尽量不超不是更好);二来,通过对象的 public 属性直接读写比使用 getter/setter 速度要快(听说的,没有验证过)。

注意:这里建议在全局常量类(没有,那就定义一个,下面会介绍)中定义一个唯一的 INTENT_EXTRA_KEY,往 Bundle 中存和取得时候都用它,也不用去为命名 key 费神(命名从来不简单,不是吗),取的时候也不用思考是用什么 key 存的,简单又可以避免犯错。

具体如下图所示:


导航管理类-跳转需要传递数据的页面

导航管理类-传递数据

导航管理类-获取传递的数据


导航管理类代码如下:

//==========逻辑方法==========
    public static <T> T getParcelableExtra(Activity activity) {
        Parcelable parcelable = activity.getIntent().getParcelableExtra(NavigateManager.PARCELABLE_EXTRA_KEY);
        activity = null;
        return (T)parcelable;
    }

    private static void overlay(Context context, Class<? extends Activity> targetClazz, int flags, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        setFlags(intent, flags);
        putParcelableExtra(intent, parcelable);
        context.startActivity(intent);
        context = null;
    }

    private static void overlay(Context context, Class<? extends Activity> targetClazz, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        putParcelableExtra(intent, parcelable);
        context.startActivity(intent);
        context = null;
    }

    private static void overlay(Context context, Class<? extends Activity> targetClazz, Serializable serializable) {
        Intent intent = new Intent(context, targetClazz);
        putSerializableExtra(intent, serializable);
        context.startActivity(intent);
        context = null;
    }

    private static void overlay(Context context, Class<? extends Activity> targetClazz) {
        Intent intent = new Intent(context, targetClazz);
        context.startActivity(intent);
        context = null;
    }

    private static void forward(Context context, Class<? extends Activity> targetClazz, int flags, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        setFlags(intent, flags);
        intent.putExtra(PARCELABLE_EXTRA_KEY, parcelable);
        context.startActivity(intent);
        if (isActivity(context)) return;
        ((Activity)context).finish();
        context = null;
    }

    private static void forward(Context context, Class<? extends Activity> targetClazz, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        putParcelableExtra(intent, parcelable);
        context.startActivity(intent);
        if (isActivity(context)) return;
        ((Activity)context).finish();
        context = null;
    }

    private static void forward(Context context, Class<? extends Activity> targetClazz, Serializable serializable) {
        Intent intent = new Intent(context, targetClazz);
        putSerializableExtra(intent, serializable);
        context.startActivity(intent);
        if (isActivity(context)) return;
        ((Activity)context).finish();
        context = null;
    }

    private static void forward(Context context, Class<? extends Activity> targetClazz) {
        Intent intent = new Intent(context, targetClazz);
        context.startActivity(intent);
        if (isActivity(context)) return;
        ((Activity)context).finish();
        context = null;
    }

    private static void startForResult(Context context, Class<? extends Activity> targetClazz, int flags) {
        Intent intent = new Intent(context, targetClazz);
        if (isActivity(context)) return;
        ((Activity)context).startActivityForResult(intent, flags);
        context = null;
    }

    private static void startForResult(Context context, Class<? extends Activity> targetClazz, int flags, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        if (isActivity(context)) return;
        putParcelableExtra(intent, parcelable);
        ((Activity)context).startActivityForResult(intent, flags);
        context = null;
    }

    private static void setResult(Context context, Class<? extends Activity> targetClazz, int flags, Parcelable parcelable) {
        Intent intent = new Intent(context, targetClazz);
        setFlags(intent, flags);
        putParcelableExtra(intent, parcelable);
        if (isActivity(context)) return;
        ((Activity)context).setResult(flags, intent);
        ((Activity)context).finish();
    }

    private static boolean isActivity(Context context) {
        if (!(context instanceof Activity)) return true;
        return false;
    }

    private static void setFlags(Intent intent, int flags) {
        if (flags < 0) return;
        intent.setFlags(flags);
    }

    private static void putParcelableExtra(Intent intent, Parcelable parcelable) {
        if (parcelable == null) return;
        intent.putExtra(PARCELABLE_EXTRA_KEY, parcelable);
    }

    private static void putSerializableExtra(Intent intent, Serializable serializable) {
        if (serializable == null) return;
        intent.putExtra(PARCELABLE_EXTRA_KEY, serializable);
    }

传递数据用的序列化对象,如下:

public class DishesStockVO implements Parcelable {

    public boolean isShowMask; 
    public int pageNum; 

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeByte(isShowMask ? (byte) 1 : (byte) 0);
        dest.writeInt(this.pageNum);
    }

    public DishesStockVO() {
    }

    protected DishesStockVO(Parcel in) {
        this.isShowMask = in.readByte() != 0;
        this.pageNum = in.readInt();
    }

    public static final Creator<DishesStockVO> CREATOR = new Creator<DishesStockVO>() {
        public DishesStockVO createFromParcel(Parcel source) {
            return new DishesStockVO(source);
        }

        public DishesStockVO[] newArray(int size) {
            return new DishesStockVO[size];
        }
    };

    @Override
    public String toString() {
        return "DishesStockVO{" +
                "isShowMask=" + isShowMask +
                ", pageNum=" + pageNum +
                '}';
    }
}

好像,还没入正题。这里再多说一句,beautifulSoup 写了一篇文章,说的就是 Android 路由表框架的,可以去看看——“Android路由框架设计与实现”。

好了,回到主题,在 Presenter 中该如何处理页面跳转的问题。在这里我建议简单处理,在 View Interface 中定义好接口(方法),在 View 的实现类中去处理(本来就是它的责任,不是吗?)。在 View 的实现类中,使用 NavigationManager 工具类跳转,达到解耦的目的。如下图所示:


对页面跳转的处理


显示对话框
我在这里采用和页面跳转的处理类似的方案,这也是 View 的责任,所以让 View 自己去完成。这里建议每个模块都定义一个相应的 XxxDialogManager 类,来管理该模块所有的弹窗,当然对于弹窗本来就不多的,那就直接在 util 包中定义一个 DialogManager 类就好了。如下图:


对显示对话框的处理

5.5.3. 一个页面多个View的问题

对于复杂页面,一般建议拆成多个自定义 View,那么这就引出一个问题,这时候是用一个 Presenter 好,还是定义多个 Presenter 好呢?我的建议是,每个 View Interface 对应一个 Presenter,如下图所示:


一个页面多个 View 处理

5.5.4. 一个View有两个实现类的问题

有些时候会遇到这样的问题,只是展示上有差别,两个页面上所有的操作都是一样的,这就意味着 View Interface 是一样的,只是有两个实现类。

这个问题该怎么处理,或许可以继续使用同样的Presenter并在另一个Android组件中实现View接口。不过这个界面似乎有更多的功能,那要不要把这些新功能加进这个Presenter呢?这个视情况而定,有多种方案:一是将Presenter整合负责不同操作,二是写两个Presenter分别负责操作和展示,三是写一个Presenter包含所有操作(在两个View相似时)。记住没有完美的解决方案,编程的过程就是让步的过程。(参考自:Christian Panadero PaNaVTEC 的 Modeling my presentation layer
如下图所示:


一个 View 多个实现类处理

5.6. 关于 RestAPI

一般项目当中会用到很多和服务器端通信用的接口,这里建议在每个模块中都建立一个 api 包,在该包下来统一处理该模块下所有的 RestAPI。
如下图所示:


统一管理 RestAPI


对于网络请求之类需要异步处理的情况,一般都需要传入一个回调接口,来获取异步处理的结果。对于这种情况,我建议参考 onClick(View v) {} 的写法。那就是为每一个请求编一个号(使用 int 值),我称之为 taskId,可以将该编号定义在各个模块的常量类中。然后在回调接口的实现类中,可以在回调方法中根据 taskId 来统一处理(一般是在这里分发下去,分别调用不同的方法)。
如下图所示:


定义 taskId

异步任务回调处理

5.6. 关于项目中的常量管理

Android 中不推荐使用枚举,推荐使用常量,我想说说项目当中我一般是怎么管理常量的。
灵感来自 R.java 类,这是由项目构建工具自动生成并维护的,可以进去看看,里面是一堆的静态内部类,如下图:


Android 中的 R 文件


看到这,可能大家都猜到了,那就是定义一个类来管理全局的常量数据,我一般喜欢命名为 C.java。这里有一点要注意,我们的项目是按模块划分的包,所以会有一些是该模块单独使用的常量,那么这些最好不要写到全局常量类中,否则会导致 C 类膨胀,不利于管理,最好是将这些常量定义到各个模块下面。如下图所示:


全局常量 C 类

5.7. 关于第三方库

Android 开发中不可避免要导入很多第三方库,这里我想谈谈我对第三方库的一些看法。关于第三方库的推荐我就不做介绍了,很多专门说这方面的文章。

5.7.1. 挑选第三方库的一些建议

  1. 项目中确实需要(这不是废话吗?用不着,我要它干嘛?呵呵,建议不要为了解决一个小小的问题导入一个大而全的库)
  2. 使用的人要多(大家都在用的一般更新会比较快,出现问题解决方案也多)
  3. 效率和体量的权衡(如果效率没有太大影响的情况下,我一般建议选择体量小点的,如,Gson vs Jackson,Gson 胜出;还是 65K 的问题)

5.7.2. 使用第三方库尽量二次封装

为什么要二次封装?
为了方便更换,说得稍微专业点为了降低耦合。
有很多原因可能需要你替换项目中的第三方库,这时候如果你是经过二次封装的,那么很简单,只需要在封装类中修改一下就可以了,完全不需要去全局检索代码。
我就遇到过几个替换第三方库的事情:

  1. 替换项目中的统计埋点工具
  2. 替换网络框架
  3. 替换日志工具

那该怎么封装呢?
一般的,如果是一些第三方的工具类,都会提供一些静态方法,那么这个就简单了,直接写一个工具类,提供类似的静态方法即可(就是用静态工厂模式)。
如下代码所示,这是对系统 Log 的简单封装:

/**
 * Description: 企业中通用的Log管理
 * 开发阶段LOGLEVEL = 6
 * 发布阶段LOGLEVEL = -1
 */

public class Logger {

    private static int LOGLEVEL = 6;
    private static int VERBOSE = 1;
    private static int DEBUG = 2;
    private static int INFO = 3;
    private static int WARN = 4;
    private static int ERROR = 5;

    public static void setDevelopMode(boolean flag) {
        if(flag) {
            LOGLEVEL = 6;
        } else {
            LOGLEVEL = -1;
        }
    }

    public static void v(String tag, String msg) {
        if(LOGLEVEL > VERBOSE && !TextUtils.isEmpty(msg)) {
            Log.v(tag, msg);
        }
    }

    public static void d(String tag, String msg) {
        if(LOGLEVEL > DEBUG && !TextUtils.isEmpty(msg)) {
            Log.d(tag, msg);
        }
    }

    public static void i(String tag, String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
            Log.i(tag, msg);
        }
    }

    public static void w(String tag, String msg) {
        if(LOGLEVEL > WARN && !TextUtils.isEmpty(msg)) {
            Log.w(tag, msg);
        }
    }

    public static void e(String tag, String msg) {
        if(LOGLEVEL > ERROR && !TextUtils.isEmpty(msg)) {
            Log.e(tag, msg);
        }
    }

}

现在如果想替换为 orhanobut 的 Logger,那很简单,代码如下:

/**
 * Description: 通用的Log管理工具类
 * 开发阶段LOGLEVEL = 6
 * 发布阶段LOGLEVEL = -1
 */

public class Logger {

    public static String mTag = "MVPBestPractice";
    private static int LOGLEVEL = 6;
    private static int VERBOSE = 1;
    private static int DEBUG = 2;
    private static int INFO = 3;
    private static int WARN = 4;
    private static int ERROR = 5;

    static {
        com.orhanobut.logger.Logger
                .init(mTag)                       // default PRETTYLOGGER or use just init()
                .setMethodCount(3)                // default 2
                .hideThreadInfo()                 // default shown
                .setLogLevel(LogLevel.FULL);      // default LogLevel.FULL
    }

    public static void setDevelopMode(boolean flag) {
        if(flag) {
            LOGLEVEL = 6;
            com.orhanobut.logger.Logger.init().setLogLevel(LogLevel.FULL);
        } else {
            LOGLEVEL = -1;
            com.orhanobut.logger.Logger.init().setLogLevel(LogLevel.NONE);
        }
    }

    public static void v(@NonNull String tag, String msg) {
        if(LOGLEVEL > VERBOSE && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.v(tag, msg);
            com.orhanobut.logger.Logger.t(tag).v(msg);
        }
    }

    public static void d(@NonNull String tag, String msg) {
        if(LOGLEVEL > DEBUG && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.d(tag, msg);
            com.orhanobut.logger.Logger.t(tag).d(msg);
        }
    }

    public static void i(@NonNull String tag, String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.t(tag).i(msg);
        }
    }

    public static void w(@NonNull String tag, String msg) {
        if(LOGLEVEL > WARN && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.w(tag, msg);
            com.orhanobut.logger.Logger.t(tag).w(msg);
        }
    }

    public static void e(@NonNull String tag, String msg) {
        if(LOGLEVEL > ERROR && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.e(tag, msg);
            com.orhanobut.logger.Logger.t(tag).e(msg);
        }
    }

    public static void e(@NonNull String tag, Exception e) {
        tag = checkTag(tag);
        if(LOGLEVEL > ERROR) {
//            Log.e(tag, e==null ? "未知错误" : e.getMessage());
            com.orhanobut.logger.Logger.t(tag).e(e == null ? "未知错误" : e.getMessage());
        }
    }

    public static void v(String msg) {
        if(LOGLEVEL > VERBOSE && !TextUtils.isEmpty(msg)) {
//            Log.v(mTag, msg);
            com.orhanobut.logger.Logger.v(msg);
        }
    }

    public static void d(String msg) {
        if(LOGLEVEL > DEBUG && !TextUtils.isEmpty(msg)) {
//            Log.d(mTag, msg);
            com.orhanobut.logger.Logger.d(msg);
        }
    }

    public static void i(String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
//            Log.i(mTag, msg);
            com.orhanobut.logger.Logger.i(msg);
        }
    }

    public static void w(String msg) {
        if(LOGLEVEL > WARN && !TextUtils.isEmpty(msg)) {
//            Log.w(mTag, msg);
            com.orhanobut.logger.Logger.v(msg);
        }
    }

    public static void e(String msg) {
        if(LOGLEVEL > ERROR && !TextUtils.isEmpty(msg)) {
//            Log.e(mTag, msg);
            com.orhanobut.logger.Logger.e(msg);
        }
    }

    public static void e(Exception e) {
        if(LOGLEVEL > ERROR) {
//            Log.e(mTag, e==null ? "未知错误" : e.getMessage());
            com.orhanobut.logger.Logger.e(e == null ? "未知错误" : e.getMessage());
        }
    }

    public static void wtf(@NonNull String tag, String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.t(tag).wtf(msg);
        }
    }

    public static void json(@NonNull String tag, String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.t(tag).json(msg);
        }
    }

    public static void xml(@NonNull String tag, String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
            tag = checkTag(tag);
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.t(tag).xml(msg);
        }
    }

    public static void wtf(String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.wtf(msg);
        }
    }

    public static void json(String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.json(msg);
        }
    }

    public static void xml(String msg) {
        if(LOGLEVEL > INFO && !TextUtils.isEmpty(msg)) {
//            Log.i(tag, msg);
            com.orhanobut.logger.Logger.xml(msg);
        }
    }

    private static String checkTag(String tag) {
        if (TextUtils.isEmpty(tag)) {
            tag = mTag;
        }
        return tag;
    }

这里是最简单的一些替换,如果是替换网络框架,图片加载框架之类的,可能要多费点心思去封装一下,这里可以参考“门面模式”。(在这里就不展开来讲如何对第三库进行二次封装了,以后有时间专门写个帖子)

5.7.3. 建立单独的 Module 管理所有的第三库

原因前面已经说过了,而且操作也很简单。网上有不少拆分 Gradle 文件的方法,讲的都很不错。那我们就先从最简单的做起,赶快行动起来,把项目中用到的第三方库都集中到 Library Module 中来吧。

5.8. MVP vs MVVM

关于 MVP 和 MVVM 我只想说一句,它们并不是相斥的。具体它们是怎么不相斥的,markzhai 的这篇文章“MVPVM in Action, 谁告诉你MVP和MVVM是互斥的”说得很详细。

5.9. Code

抱歉,要食言了,AndroidStudio 出了点问题,代码还没写完,代码估计要这周末才能同步到 GitHub 上了,目前只上传了一个空框架。

5.10. 小结

历时三天的 MVP 总结,总算要告一段落了。前期断断续续地花了将近一周左右零散的时间去调研 MVP,直到正式开始码字的时候才发现准备的还不够。看了很多文章,有观点一致的,也有观点很不一致的。最关键的是,自己对于 MVP 还没有比较深刻的认知,所以在各种观点中取舍花了很长时间。
这算得上是我第一次真正意义上的写技术性的文章,说来惭愧,工作这么长时间了,现在才开始动笔。
总体来说,写得并不尽如人意,套一句老话——革命尚未成功,同志仍需努力。这算是一次尝试,希望以后会越写越顺畅。在这里给各位坚持看到此处的看官们问好了,祝大家一同进步。(欢迎大家围观我的GitHub,周末更新,会渐渐提交更多有用的代码的)

6. 进阶与不足

鉴于本人能力有限,还有很多想写的和该写的内容没有写出来,很多地方表达的也不是很清晰。下面说一说我觉得还有哪些不足和下一步要进阶的方向。

  1. 说好的“show me the code”,代码呢?(再次抱歉了)
  2. 上篇当中关于各种 Presenter 方案只是做了简单的罗列,并没有仔细分析各个方案的优点和不足
  3. 没有形成自己的框架(呵呵,好高骛远了,但是梦想还是要有的...)
  4. 没有单元测试(项目代码都还没有呢,提倡 TDD 不是,呵呵)
  5. 很多细节没有介绍清楚(如关于Model、Domain、Entity 等概念不是很清晰)
  6. 很多引用的观点没有指明出处(如有侵权,马上删除)
    ......

最后想说一句,没有完美的架构,没有完美的框架,赶紧编码吧!

7. 附录

Android MVP 总结资料汇总
附上我的思维导图:
MVPBestPractice.mmap
MVP总结.mmap
Presenter生命周期.mmap
怎么写Presenter.mmap

参考:
https://segmentfault.com/a/1190000003871577
http://www.open-open.com/lib/view/open1450008180500.html
http://www.myexception.cn/android/2004698.html
http://gold.xitu.io/entry/56cbf38771cfe40054eb3a34
http://kb.cnblogs.com/page/531834/
http://blog.zhaiyifan.cn/2016/03/16/android-new-project-from-0-p3/
http://www.open-open.com/lib/view/open1446377609317.html
http://my.oschina.net/mengshuai/blog/541314?fromerr=3J2TdbiW
http://gold.xitu.io/entry/56fcf1f75bbb50004d872e74
https://github.com/googlesamples/android-architecture/tree/todo-mvp-loaders/todoapp
http://blog.zhaiyifan.cn/2016/03/16/android-new-project-from-0-p3/
http://android.jobbole.com/82375/
http://blog.csdn.net/weizhiai12/article/details/47904135
http://android.jobbole.com/82051/
http://android.jobbole.com/81153/
http://blog.chengdazhi.com/index.php/115
http://blog.chengdazhi.com/index.php/131
http://www.codeceo.com/article/android-mvp-practice.html
http://www.wtoutiao.com/p/h01nn2.html
http://blog.jobbole.com/71209/
http://www.cnblogs.com/tianzhijiexian/p/4393722.html
https://github.com/xitu/gold-miner/blob/master/TODO/things-i-wish-i-knew-before-i-wrote-my-first-android-app.md
http://gold.xitu.io/entry/56cd79c12e958a69f944984c
http://blog.yongfengzhang.com/cn/blog/write-code-that-is-easy-to-delete-not-easy-to/
http://kb.cnblogs.com/page/533808/

作者:weixin_36569761 发表于2016/12/13 11:28:04 原文链接
阅读:7 评论:0 查看评论

3、Lucene实现全文检索的流程

$
0
0
1.1 案例描述
我们以一个案例来研究全文检索系统架构:实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来。
 

1.2 索引和搜索流程图


1、绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:
确定原始内容即要搜索的内容à采集文档à创建文档à分析文档à索引文档
        
2、红色表示搜索过程,从索引库中搜索内容,搜索过程包括:
用户通过搜索界面à创建查询à执行搜索,从索引库搜索à渲染搜索结果
 
1.3 索引流程
对文档索引的过程,将用户要搜索的文档内容进行索引,索引存储在索引库(index)中。
这里我们要搜索的文档是磁盘上的文本文件,根据案例描述:凡是文件名或文件内容包括关键字的文件都要找出来,这里要对文件名和文件内容创建索引。
 
 
1.3.1     原始内容
原始内容是指要索引和搜索的内容。原始内容包括互联网上的网页、数据库中的数据、磁盘上的文件等。
本案例中的原始内容就是磁盘上的文件,如下图:

1.3.2     获取原始内容(信息采集)
从互联网上、数据库、文件系统中等获取需要搜索的原始信息,这个过程就是信息采集,信息采集的目的是为了对原始内容进行索引。
Internet上采集信息的软件通常称为爬虫或蜘蛛,也称为网络机器人,爬虫访问互联网上的每一个网页,将获取到的网页内容存储起来。
    Lucene不提供信息采集的类库,需要自己编写一个爬虫程序实现信息采集,也可以通过一些开源软件实现信息采集,如下:
    Solr(http://lucene.apache.org/solr) ,solr是apache的一个子项目,支持从关系数据库、xml文档中提取原始数据。
    Nutch(http://lucene.apache.org/nutch), Nutch是apache的一个子项目,包括大规模爬虫工具,能够抓取和分辨web网站数据。
    jsoup(http://jsoup.org/ ),jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
    heritrix(http://sourceforge.net/projects/archive-crawler/files/),Heritrix 是一个由 java 开发的、开源的网络爬虫,用户可以使用它来从网上抓取想要的资源。其最出色之处在于它良好的可扩展性,方便用户实现自己的抓取逻辑。
本案例我们要获取磁盘上文件的内容,可以通过文件流来读取文本文件的内容,对于pdfdocxls等文件可通过第三方提供的解析工具读取文件内容,比如Apache POI读取docxls的文件内容。 
 
1.3.3     创建文档
获取原始内容的目的是为了索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容。
这里我们可以将磁盘上的一个文件当成一个documentDocument中包括一些Fieldfile_name文件名称、file_path文件路径、file_size文件大小、file_content文件内容),如下图:

注意:每个Document可以有多个Field,不同的Document可以有不同的Field,同一个Document可以有相同的Field(域名和域值都相同)
 
每个文档都有一个唯一的编号,就是文档id
 
1.3.4     分析文档
 
将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为一个一个的单词。
 
比如下边的文档经过分析如下:
原文档内容:
Lucene is a Java full-text search engine.  Lucene is not a complete
application, but rather a code library and API that can easily be used
to add search capabilities to applications.
 
分析后得到的语汇单元:
lucenejavafullsearchengine。。。。
 
每个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的termterm中包含两部分一部分是文档的域名,另一部分是单词的内容。
例如:文件名中包含apache和文件内容中包含的apache是不同的term
 
1.3.5     索引文档
对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
注意:创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构
传统方法是根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
倒排索引结构是根据内容(词语)找文档,如下图:

倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大。
 
 
1.4 搜索流程
搜索就是用户输入关键字,从索引(index)中进行搜索的过程。根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容(这里指磁盘上的文件)。
 
1.4.1     用户
用户可以是自然人,也可以是远程调用的程序。
 
1.4.2     用户搜索界面
全文检索系统提供用户搜索的界面供用户提交搜索的关键字,搜索完成展示搜索结果。
 
比如:

Lucene不提供制作用户搜索界面的功能,需要根据自己的需求开发搜索界面。
 
 
1.4.3     创建查询
用户输入查询关键字执行搜索之前需要先构建一个查询对象,查询对象中可以指定查询要搜索的Field文档域、查询关键字等,查询对象会生成具体的查询语法,比如:
语法 fileName:spring.txt”表示要搜索Field域的内容为“spring.txt”的文档
语法 lucene AND java 表示要搜索即包括关键字“lucene”也包括“java”的文档。
 
1.4.4     执行搜索
搜索索引过程:
1.根据查询语法在倒排索引词典表中分别找出对应搜索词的索引,从而找到索引所链接的文档链表。
比如搜索语法为“lucene AND java”表示搜索出的文档中即要包括lucene也要包括java

2、由于是AND,所以要对包含lucenejava词语的链表进行交集,得到文档链表应该包括每一个搜索词语
3、获取文档中的Field域数据。
 
1.4.5     展示结果
 
以一个友好的界面将查询结果展示给用户,用户根据搜索结果找自己想要的信息,为了帮助用户很快找到自己的结果,提供了很多展示的效果,比如搜索结果中将关键字高亮显示,百度提供的快照等。

作者:u013115157 发表于2016/12/13 11:29:41 原文链接
阅读:8 评论:0 查看评论

Retrofit使用指南

$
0
0

Retrofit使用指南

字数1991 阅读2678 评论18 

Retrofit.jpg

Retrofit简介

Retrofit是大名鼎鼎的 Square 公司开源的适用于AndroidJava的网络请求库,官方的介绍非常简短

A type-safe HTTP client for Android and Java

Retrofit使用注解,能够极大的简化网络请求,在2.0版本默认使用Square自家的OkHttp作为底层Http Client,关于如何使用OkHttp配合Retrofit本文后面也会讲到。首先在build.gradle中加入

  compile 'com.squareup.retrofit2:retrofit:2.0.2'

定义一个网络请求:

public interface ZhiHuApi {
@GET("users")
Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit将网络请求转变成了Java interface的形式,interface要获得实例调用listRepos(String user),需要借助Retrofit.java这个类,通过Retrofit.Builder来配置Retrofit,再通过retrofit.create(final Class<T> service)获取接口的实例

class Factory {

  public static ZhiHuApi create() {
    Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://news-at.zhihu.com/")
                    .build();
            return retrofit.create(ZhiHuApi.class);
        }
}

@GET注解表示请求方式为GET,其中的字符串表示相对URL,而scheme host port被认为是BaseUrl设置到Retrofit中,注意BaseUrl需要以/结尾,这样每个接口定义的相对URL就不需要以/开始。如果在接口中定义的URL为全路径,将用这个全路径作为请求URLBaseUrl将不起作用。@Path标识get请求的请求参数,上面的listRepos可以认为是在请求http://news-at.zhihu.com/users?user=user
@POST注解表示请求方式为POST,通常和@FormUrlEncoded注解一起使用,在使用@FormUrlEncoded时可以使用@Field标识表单字段

@FormUrlEncoded
@POST("user/login.do")
Call<User> login(@Field("username") String userName, @Field("password") String password);

或者使用@FieldMap提交整个map

@FormUrlEncoded
@POST("user/login.do")
Call<User> login(@FieldMap Map<String, String> formMap);

当然你也可以把整个表单封装为一个实体,使用@Body一次提交

@FormUrlEncoded
@POST("user/login.do")
Call<User> login(@Body User user);

Multipart请求时使用@Multipart注解,用@Part标识每个RequestBody

@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

定义好请求之后就可以调用call.enqueue()来执行请求,需要传入Callback<T>,其中T的类型编译器会根据Call<T>中的类型来判断,Retrofit和其他网络请求库一样对于Android 平台做了线程切换,请求在后台执行,Callback<T>会回到main (UI) thread,如果是Java程序Callback<T>会继续回到调用它的线程。

ZhiHuApi zhiHuApi = BaseNetwork.Factory.create(ZhiHuApi.class);
        Call<User> call = zhiHuApi.login("username", "pwd");
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {

            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {

            }
        });

为请求添加请求头时使用@Headers,这里就不做举例,因为app中通常是每个请求都需要携带请求头,不建议在Retrofit定义请求时传入,而是使用OkHttp来实现统一请求头。

Converter

Retrofit在默认情况下只能将Http的响应体反序列化到OkHttpResponseBody中,加入Converter可以将返回的数据直接格式化成你需要的样子,现有6个Converter可以直接使用:

  • Gson: com.squareup.retrofit2:converter-gson
  • Jackson: com.squareup.retrofit2:converter-jackson
  • Moshi: com.squareup.retrofit2:converter-moshi
  • Protobuf: com.squareup.retrofit2:converter-protobuf
  • Wire: com.squareup.retrofit2:converter-wire
  • Simple XML: com.squareup.retrofit2:converter-simplexml
  • Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars

之后在代码里加入(此处以GsonConverterFactory为例)

  Retrofit retrofit =new Retrofit.Builder()
                    .baseUrl(Constants.BASE_HTTP_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

返回的数据会使用Gson解析为对应传入的实体类,你也可以自定义Converter来实现更复杂的需求,只需要extends Converter.Factory然后重写

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
        //your own implements
  }

  @Override
  public Converter<?, RequestBody> requestBodyConverter(Type type,
     Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
       //your own implements
  }

Retrofit终归只是应用层的api,真正的执行器是OkHttp,较为复杂的需求都需要从执行层入手,可以做到Retrofit对外不变的多种自定义统一封装。

OkHttp配合Retrofit使用

前文已经提到在Retrofit 2.0中已经默认使用OkHttp作为网络请求执行器,关于OkHttp的优点简单提一下:(原文链接)

  • 1.支持HTTP2/SPDY黑科技
  • 2.socket自动选择最好路线,并支持自动重连
  • 3.拥有自动维护的socket连接池,减少握手次数
  • 4.拥有队列线程池,轻松写并发
  • 5.拥有Interceptors轻松处理请求与响应(比如透明GZIP压缩,LOGGING)
  • 6.基于Headers的缓存策略

想要使用OkHttpRetrofit提供更高的定制性,给Retrofit设置自定义的OkHttpClient就可以了

Retrofit retrofit = new Retrofit.Builder()
                  .baseUrl(Constants.BASE_HTTP_URL)
                  .client(client)
                  .build();

之后就是构建一个OkHttpClient

OkHttpClient client = new OkHttpClient.Builder()
           // 向Request Header添加一些业务相关数据,如APP版本,token
           .addInterceptor(new HeadInterceptor())
           //日志Interceptor,可以打印日志
           .addInterceptor(logging)
           // 连接超时时间设置
           .connectTimeout(10, TimeUnit.SECONDS)
           // 读取超时时间设置
           .readTimeout(10, TimeUnit.SECONDS)
           // 失败重试
           .retryOnConnectionFailure(true)
           // 支持Https需要加入SSLSocketFactory
           .sslSocketFactory(sslSocketFactory)
           // 信任的主机名,返回true表示信任,可以根据主机名和SSLSession判断主机是否信任
           .hostnameVerifier(new HostnameVerifier() {
               @Override
               public boolean verify(String hostname, SSLSession session) {
                   return true;
               }
           })
           // 使用host name作为cookie保存的key
           .cookieJar(new CookieJar() {
               private final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();

               @Override
               public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                   cookieStore.put(HttpUrl.parse(url.host()), cookies);
               }

               @Override
               public List<Cookie> loadForRequest(HttpUrl url) {
                   List<Cookie> cookies = cookieStore.get(HttpUrl.parse(url.host()));
                   return cookies != null ? cookies : new ArrayList<Cookie>();
               }
           })
           .build();

如果设置了sslSocketFactory却没有配置对应的hostnameVerifier,那么Https请求是无法成功的。上面用到两个Interceptor分别是HeadInterceptorHttpLoggingInterceptor,分别是用来添加请求头和打印请求日志的拦截器,OkHttp支持自定义拦截器,例如下面代码自定义的HeadInterceptor为请求加入Headers

public class HeadInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        Request compressedRequest = originalRequest.newBuilder()
                .headers(Headers.of(getHeaders()))
                .build();
        return chain.proceed(compressedRequest);
    }
}

有时服务器会对POST提交的表单做参数校验,一种方式是在请求头里加入特定方式加密过的表单参数的Map,那么就需要先获取到请求的Map,通过FormBody可以实现

// if the server needs to verify post params, use this to get post params;
  RequestBody oidBody = originalRequest.body();
  Map<String, String> params = new HashMap<>();
  if (oidBody instanceof FormBody) {
    FormBody formBody = (FormBody) oidBody;
    for (int i = 0; i < formBody.size(); i++) {
        params.put(formBody.encodedName(i), formBody.encodedValue(i));
    }
  }

HttpLoggingInterceptor是 Square 提供的请求信息日志打印工具类,如果需要可以在build.gradle中加入

  compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'

可以根据不同情况配置日志输出的Level

  • NONE 不输出日志
  • BASIC 只输出请求方式响应码等基本信息
  • HEADERS 只输出请求和响应的头部信息
  • BODY 输出请求和响应的头部和请求体信息

另外如果遇到两个接口有相互依赖关系,必须请求完第一个接口拿到数据后才知道第二个请求的URL,通常我们会定义两个Retrofit,因为RetrofitBaseUrl是统一配置的,不过现在可以通过实现动态BaseUrl来避免这个问题,先看DynamicBaseUrlInterceptor的代码

public class DynamicBaseUrlInterceptor implements Interceptor {
    private volatile String host;

    public void setHost(String host) {
        this.host = host;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        if (!TextUtils.isEmpty(host)) {
            HttpUrl newUrl = originalRequest.url().newBuilder()
                    .host(host)
                    .build();
            originalRequest = originalRequest.newBuilder()
                    .url(newUrl)
                    .build();
        }

        return chain.proceed(originalRequest);
    }
}

BaseUrl改变时只需要setHost()就可以让下次请求的Baseurl改变

Retrofit 与 RxJava 结合使用

本节需要对RxJava基本用法有了解,如果不了解可以忽略或者先去熟悉一下RxJavawiki,介绍的目的是因为两者结合使用确实很方便,关于RxJava之后会单独写。

RxJavaRx(全称Reactive Extensions)家族中的一员,是最近很火的响应式编程库,官方对于它的解释很简单

RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

一个异步的基于事件的观察者序列,可以理解为扩展的观察者模式,在 Android 中使用RxJava需要引入两个compileRxAndroid是专为 Android 平台打造来提供主线程切换等便利的工具项目。

   compile 'io.reactivex:rxandroid:1.2.0'
   // Because RxAndroid releases are few and far between, it is recommended you also
   // explicitly depend on RxJava's latest version for bug fixes and new features.
   compile 'io.reactivex:rxjava:1.1.5'

Retrofit提供了CallAdapterFactory,它是一个知道如何将call实例转换成其他类型的工厂类,目前支持的有:

  • RxJava
  • Guava
  • Java8

这些和Retrofit本身都是分离的,需要单独引入compile例如

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'

在代码中配置CallAdapterFactory

Retrofit retrofit =new Retrofit.Builder()
                   .baseUrl(Constants.BASE_HTTP_URL)
                   .addConverterFactory(GsonConverterFactory.create())
                   .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                   .build();

之后就可以把请求的返回改为Observable<T>

@GET("users")
Observable<List<Repo>> listRepos(String user);

请求时只需要

BaseNetwork.Factory.create(Foo.class)
                .listRepos("user")
                .observeOn(AndroidSchedulers.mainThread())//观察者所在的线程
                .subscribeOn(Schedulers.io())//请求执行的线程
                //如果正常执行会顺序调用onNext,onCompleted,如果出错则会调用onError
                .subscribe(new Observer<List<Repo>>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(List<Repo> list) {

                    }
                });

如果需要配合服务器返回固定的格式,通过状态码判断业务是否出错,如果出错获取错误信息,类似如下格式

{
  "state":0,//状态码,0为业务正常
  "msg":"",//如果业务出错,携带错误信息
  "data":{}//包含实际业务实体
}

需要定义统一的响应实体,根据T传入的类型来获取业务实体真实的类型

public class BaseResult<T> {
    private int state;
    private String msg;
    private T data;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

请求中的泛型类型需要是BaseResult<T>

@GET("users")
Observable<BaseResult<List<Repo>>> listRepos(@Path("user") String user);

调用时也会有改变,需要经过一次拆解统一返回,处理错误的过程

BaseNetwork.Factory.create(Foo.class)
                .listRepos("user")
                .flatMap(new NetworkResultFunc1<List<Repo>>())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(observer);

flatMap需要传入Func1<T, R>,Func1<T, R>继承了Function,只有一个方法,将泛型参数列表的第一个转换为第二个返回,它可以将Observable做一个展开,并返回一个新的Observable

public interface Func1<T, R> extends Function {
    R call(T t);
}

NetworkResultFunc1<List<Repo>>实现了Func1<T, R>,代码如下

public class NetworkResultFunc1<T> implements Func1<BaseResult<T>, Observable<T>> {

    @Override
    public Observable<T> call(final BaseResult<T> tBaseResult) {
        return Observable.create(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {
                int state = tBaseResult.getState();
                String msg = tBaseResult.getMsg();
                switch (state) {
                    case 0://if success, return data to client
                        subscriber.onNext(tBaseResult.getData());
                        break;
                    case 1000://if this means error
                        subscriber.onError(new ApiException(state, msg));
                        break;
                }
                subscriber.onCompleted();//no error, will execute onCompleted()
            }
        });
    }
}

如果state为0,则调用subscriber.onNext()向调用者返回数据,当state不等于0时意味着业务出错了,向subscriber.onError()中抛了一个ApiException,这样在Observer处会回调onError()终止整个事件流,调用者也能获得业务错误的相关信息。ApiException代码如下,就是一个自定义的RuntimeException

public class ApiException extends RuntimeException {
    private int state;
    private String msg;
    public ApiException(int state, String msg) {
        this.state = state;
        this.msg = msg;
    }

    public int getState() {
        return state;
    }

    public String getMsg() {
        return msg;
    }
}

对于Retrofit的介绍就先到这里,相信看到这里,你已经能够在项目中优雅的使用Retrofit了。

作者:weixin_36569761 发表于2016/12/13 11:30:12 原文链接
阅读:2 评论:0 查看评论

设计模式之建造者模式

$
0
0

建造者模式(Builder Pattern)也叫做生成器模式,今天让我们一起学习一下建造者模式。

一、基本介绍

建造者模式的定义为:将一个复杂对象的构建和它的表示分离开,使得同样的构建过程可以创建不同的表示。

建造者模式主要由4个角色来组成:

1 . 抽象建造者(Builder)角色:该角色用于规范产品的各个组成部分,并进行抽象,一般独立于应用程序的逻辑。

2 . 具体建造者(Concrete Builder)角色:该角色实现抽象建造者中定义的所有方法,并且返回一个组建好的产品实例。

3 . 产品(Product)角色:该角色是建造者中的复杂对象,一个系统中会有多于一个的产品类,这些产品类并不一定有共同的接口,完全可以是不相关联的。

4 . 导演者(Director)角色:该角色负责安排已有模块的顺序,然后告诉Builder开始建造。

二、代码实现建造者模式

上面说的东西都只是理论,多少有些空洞,现在我们就通过一个简单的例子来体验一下建造者模式。

1 . 创建产品类Product.java

/**
 * 产品类
 *
 */
public class Product {
    //业务处理方法
}

由于我们的目的是最终生产产品,所以产品类中的逻辑实现我们暂且不关注,具体的方法要根据业务来写。

2 . 创建抽象建造者类Builder.java

/**
 * 抽象建造者类
 *
 */
public abstract class Builder {
    //设置产品的不同部分,以获得不同的产品
    public abstract void setPart1();
    public abstract void setPart2();
    public abstract void setPart3();

    //建造产品
    public abstract Product builderProduct();
}

该类是一个抽象类,其中我们声明了4个抽象方法,前面三个是负责给产品添加不同的部件,第四个方法是负责建造产品。但这只是一个框架,还没有具体的实现。

3 . 创建具体建造者类ConcreteBuilder.java

/**
 *具体建造者类
 *
 */
public class ConcreteBuilder extends Builder{
    //一个产品
    private Product product = new Product();

    //开始安装产品的部件
    @Override
    public void setPart1() {
        //为product安装部件1
    }

    @Override
    public void setPart2() {
        //为product安装部件2
    }

    @Override
    public void setPart3() {
        //为product安装部件3
    }

    //建造一个产品
    @Override
    public Product builderProduct() {
        // TODO Auto-generated method stub
        return product;
    }
}

该类会继承自抽象建造者类Builder,并实现其中的方法。开始先声明一个产品,然后在各个setPart3方法中添加具体的逻辑,然后在builderProduct()方法中返回生产好的产品。

4 . 创建导演类Director()

上面我们已经实现了具体的建造者类,也具体写好了安装每个部件的方法,最后一步就是由导演类来知道具体构建者类如何制造产品啦。制造完的产品会交给导演类负责处理。

/**
 * 导演类
 *
 */
public class Director1 {
    private Builder builder = new ConcreteBuilder();

    //构建产品,调用各个添加部件的方法
    public Product build(){
        builder.setPart1();
        builder.setPart2();
        builder.setPart3();
        //调用构建产品的方法来构建产品
        return builder.builderProduct();
    }
}

这个类很简单,其实就是获得一个具体的建造者对象,然后调用具体的方法给产品安装部件,安装完成后调用builder.builderProduct()方法获得建造好的产品,此处导演类是在build()方法中完成了建造过程,同时将获得的建造好的产品返回出去,以供其他模块使用该产品。

此处的导演类起到了封装左右,可以避免高层模块深入到建造者内部的实现类,而且导演类可以有多个,根据业务逻辑分别用来建造不同的产品并输出。

三、建造者模式的优点

建造者模式的有点主要有以下几点:

1 . 封装性。使用建造者模式可以使客户端不必知道产品的内部实现细节

2 . 独立易扩展。由于建造过程是独立的,更利于后期扩展

3 . 便于控制细节风险。由于具体的产品建造是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响

四、建造者模式的使用场景

说了这么多建造者模式的好处,那我们应该在什么场合使用它们呢,看下面:

1 . 相同的方法,不同的执行顺序,产生不同的结果。这种情况我们只要利用不同的导演类来控制建造过程,就可以产生不同的产品,其他部分不用修改

2 . 多个零件和部件,都可以装配到一个对象中,装配不同的零件,产生不同的运行结果,我们同样可以通过修改导演类来产生不同的产品

3 . 产品类非常复杂,此时我们也可以将产品的建造方法和具体的建造顺序分离开来处理

4 . 在对象创建过程中会用到系统的一些其他对象,这些对象在产品对象的创建过程中不容易得到,可以采用建造者模式封装该对象的创建过程

注:建造者模式关注的是零件的类型和装配工艺的顺序

五、建造者模式实站

说了半天建造产品,没行动有卵用,来来来,咋们就用刚学的建造者模式生产两台不同类型的电脑练练手,代码敲起来

1 . 创建产品父类Computer

该类是我们建造的计算机的父类,其中包含了计算机的公共属性以及属性的get和set方法

package cn.codekong.start;

/**
 * 计算机类
 */
public class Computer {
    //型号
    private String type;
    //CPU
    private String cpu;
    //内存
    private String ram;
    //硬盘
    private String hardDisk;
    //显示器
    private String monitor;
    //操作系统
    private String os;

    //对应的get和set方法
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public String getHardDisk() {
        return hardDisk;
    }
    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }
    public String getMonitor() {
        return monitor;
    }
    public void setMonitor(String monitor) {
        this.monitor = monitor;
    }
    public String getOs() {
        return os;
    }
    public void setOs(String os) {
        this.os = os;
    }
}

2 . 创建具体的产品类T410类和X201

这两个类均继承自上面的Computer类,并且我们在该类在添加了两台计算机特有的属性,T410计算机用于独立显卡,而X201没有,同时重写了它们的toString()方法,返回它们的参数,便于最后我们建造完计算机后输出它们各自的配置参数.

T410.java
package cn.codekong.start;

public class T410 extends Computer{
    //显卡
    private String graphicCard;
    public T410() {
        this.setType("Thinkpad T410");
    }

    public String getGraphicCard(){
        return graphicCard;
    }

    public void setGraphicCard(String graphicCard){
        this.graphicCard = graphicCard;
    }

    @Override
    public String toString() {
        return "型号:\t" + this.getType() + "\nCPU\t" + this.getCpu()
                + "\n内存\t" + this.getRam() + "\n硬盘\t" + this.getHardDisk()
                + "\n显卡\t" + this.getGraphicCard() + "\n显示器\t" + this.getMonitor()
                + "\n操作系统\t" + this.getOs();
    }
}
X201.java
package cn.codekong.start;

public class X201 extends Computer{
    public X201() {
        this.setType("Thinkpad X201");
    }
    @Override
    public String toString() {
        return "型号:\t" + this.getType() + "\nCPU\t" + this.getCpu()
                + "\n内存\t" + this.getRam() + "\n硬盘\t" + this.getHardDisk()
                + "\n显示器\t" + this.getMonitor() + "\n操作系统\t" + this.getOs();
    }
}

上面的(1)(2)步只是相当于我们有了我们需要的产品类已经声明好了,下面开始写我们的抽象建造类

3 . 抽象计算机建造类ComputerBuilder

我们创建了一个接口,在其中声明了我们要建造产品过程中需要用到的方法,其实就是产品的各个建造步骤

package cn.codekong.start;
/**
 * 抽象的计算机建造者
 * 声明建造的公共方法
 */
public interface ComputerBuilder {
    //建造CPU
    void buildCpu();
    //建造内存
    void buildRam();
    //建造硬盘
    void buildHardDisk();
    //建造显卡
    void buildGraphicCard();
    //建造显示器
    void buildMonitor();
    //建造操作系统
    void buildOs();

    //得到建造好的计算机
    Computer getResult();
}

4 . 创建具体的建造类T410Builder类和X201Builder

这两个类要实现上一步定义的接口,然后实现里面的各个方法,其实就是实现各个具体的组装方法中的逻辑,但此时只是把每一个组装的步骤的逻辑具体化了,还没有开始正式组装。

T410Builder.java
package cn.codekong.start;

/**
 * T410的具体建造者实现抽象的计算机建造者
 */
public class T410Builder implements ComputerBuilder{
    private T410 computer = new T410();
    @Override
    public void buildCpu() {
        computer.setCpu("i5-450");
    }

    @Override
    public void buildRam() {
        computer.setRam("4G 1333MHz");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("500G 7200转");
    }

    @Override
    public void buildGraphicCard() {
        computer.setGraphicCard("Nvidia");
    }

    @Override
    public void buildMonitor() {
        computer.setMonitor("14英寸 1280*800");
    }

    @Override
    public void buildOs() {
        computer.setOs("Windows7 旗舰版");
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}
X201Builder.java
package cn.codekong.start;

/**
 * X201计算机的具体建造类实现抽象的计算机建造类
 */
public class X201Builder implements ComputerBuilder{
    private X201 computer = new X201();
    @Override
    public void buildCpu() {
        computer.setCpu("i3-350");
    }

    @Override
    public void buildRam() {
        computer.setRam("2G 1333M");
    }

    @Override
    public void buildHardDisk() {
        computer.setHardDisk("250G 5400 转");
    }

    @Override
    public void buildGraphicCard() {
        //无独立显卡
    }

    @Override
    public void buildMonitor() {
        computer.setMonitor("12英寸 1280*800");
    }

    @Override
    public void buildOs() {
        computer.setOs("Windows7 Home版");
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

5 . 导演类知道具体的建造者类建造产品ComputerDirector

该类就比较简单了,在该类内部实现两个构造方法,分别对应实现两种计算机的过程,这时候才是正式的建造过程。

package cn.codekong.start;

/**
 * 计算机导演类,知道具体建造者建造计算机
 */
public class ComputerDirector {
    ComputerBuilder builder;

    //建造T410计算机
    public T410 constructT410(){
        builder = new T410Builder();
        builder.buildCpu();
        builder.buildRam();
        builder.buildHardDisk();
        builder.buildGraphicCard();
        builder.buildMonitor();
        builder.buildOs();
        //建造结束将产品返回供外部使用
        return (T410)builder.getResult();
    }

    //建造X201计算机
    public X201 constructX201(){
        builder = new X201Builder();
        builder.buildCpu();
        builder.buildRam();
        builder.buildHardDisk();
        //由于X201没有独立显卡,则不调用buildGraphicCard()函数
        //builder.buildGraphicCard();

        builder.buildMonitor();
        builder.buildOs();
        //建造结束将产品返回供外部使用
        return (X201)builder.getResult();
    }
}

6 . 最后让我们测试一下建造的产品是否是好的,新建测试类ComputerTest

package cn.codekong.start;

/**
 * 计算机建造测试类
 */
public class ComputerTest {
    public static void main(String[] args) {
        ComputerDirector computerDirector = new ComputerDirector();
        //建造T410计算机
        Computer t410 = computerDirector.constructT410();
        //输出T410计算机的配置参数
        System.out.println(t410);

        System.out.println("------------我是分割线----------------");

        //建造X201计算机
        Computer x201 = computerDirector.constructX201();
        //输出X201的计算机配置
        System.out.println(x201);
    }
}

输出结果如下

型号: Thinkpad T410
CPU i5-450
内存  4G 1333MHz
硬盘  500G 7200转
显卡  Nvidia
显示器 14英寸 1280*800
操作系统    Windows7 旗舰版
------------我是分割线----------------
型号: Thinkpad X201
CPU i3-350
内存  2G 1333M
硬盘  250G 5400 
显示器 12英寸 1280*800
操作系统    Windows7 Home版

好了,经过上面的步骤,我们的产品就建造好咯。


这时候有人会说,你这个例子还是不接地气啊,我怎么没见过什么程序这么写呢,好,那咋就来一个接地气的例子,看下面的代码:

AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setTitle("我是标题")
                .setIcon(R.drawable.icon)
                .show();

上面是一个Android里面警告框的例子,我们可以通过链式调用的方法将标题和图标传入,然后调用show()方法就构建了一个警告框。这个例子是不是很常见,那我们就用一个类使用建造者模式实现一下吧:

package com.codekong.my;

import javax.naming.Context;

public class MyDialog {
    //警告框标题
    private String title;
    //警告框图标资源Id
    private int iconId;
    //上下文环境
    private Context context;
    public String getTitle() {
        return title;
    }

    public int getIconId() {
        return iconId;
    }

    public Context getContext() {
        return context;
    }

    public static class Builder{
        //设置默认值
        private String title = "Title";
        private int iconId = 0;
        private Context context;
        public Builder(Context context){
            this.context = context;
        }

        public Builder setTitle(String title) {
            this.title = title;
            return this;
        }

        public Builder setIconId(int iconId) {
            this.iconId = iconId;
            return this;
        }

        //应用我们的设置
        private void applyConfig(MyDialog myDialog){
            myDialog.title = title;
            myDialog.iconId = iconId;
            myDialog.context = context;
        }

        public MyDialog show(){
            MyDialog myDialog = new MyDialog();
            applyConfig(myDialog);
            return myDialog;
        }

    }
}

上面的类主要涉及到以下几步:

1 . 创建一个类,先声明他的成员变量以及成员变量的get方法(其实这一步就是建造者模式里面的产品角色,get方法是为了我们使用时可以随时查看我们自定义的产品属性)

2 . 定义一个静态内部类Builder,然后把我们产品定义的属性在静态内部类中复制一份,同时生成它的set方法(这一步呢其实就是我们的抽象建造者角色,要注意的一点是为了实现链式调用,我们要让我们的set方法返回值为Builder, 同时在set方法中返回this,也就是返回本对象)

3 . 接着定义applyConfig()方法,把我们通过set方法设置的值全部赋值给我们的外部类对应的成员变量(这一步就是我们的具体的建造者角色)

4 . 最后对外提供一个show()方法,在其中先 new 出一个我们的MyDialog对象,然后把它传入调用applyConfig()方法,调用过后我们的myDialog对象就已经被设置属性了,我们此时就可以将这个设置过的对象传到外部供其他类使用(这一步就是我们的导演角色)

当我们使用的时候就可以通过下面代码使用:

MyDialog myDialog = new MyDialog.Builder(this)
        .setTitle("我是标题")
        .setIconId(R.drawable.icon)
        .show();

六、后记

以上就是建造者模式的全部内容,希望可以帮助到有需要的人.

作者:bingjianIT 发表于2016/12/13 11:37:14 原文链接
阅读:71 评论:0 查看评论

以springMVC+spring+hibernate为框架的项目搭建步骤

$
0
0

一.所需要的jar包:
这里写图片描述
二.配置的文件

<?xml version="1.0" encoding="UTF-8"?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                            http://www.springframework.org/schema/context 
                            http://www.springframework.org/schema/context/spring-context-3.0.xsd
                            http://www.springframework.org/schema/tx 
                            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                            http://www.springframework.org/schema/aop 
                            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 

    <!-- 1:添加组件对注解的支持 -->
    <context:component-scan base-package="com.itheima.elec"/>
    <!-- 2:c3p0连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/项目名?useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="user" value="root" />
        <property name="password" value="root" />
        <!--连接池中保留的最小连接数。-->
        <property name="minPoolSize" value="5" />

        <!--连接池中保留的最大连接数。Default: 15 -->
        <property name="maxPoolSize" value="30" />

        <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
        <property name="initialPoolSize" value="10"/>

        <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
        <property name="maxIdleTime" value="60"/>

        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
        <property name="acquireIncrement" value="5" />

        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements  
            属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。  
            如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
        <property name="maxStatements" value="0" />

        <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
        <property name="idleConnectionTestPeriod" value="60" />

        <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
        <property name="acquireRetryAttempts" value="30" />

        <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效  
            保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试  
            获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
        <property name="breakAfterAcquireFailure" value="true" />
    </bean>
    <!-- 3:spring整合hibernate的核心 -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation">
            <value>
                classpath:hibernate.cfg.xml
            </value>
        </property>
    </bean>
    <!-- 4:创建事务管理器 -->
    <bean id="trManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"></property>
    </bean>
    <!-- 5:事务处理:注解,在Service层填写一个注解@Transcational -->
    <tx:annotation-driven transaction-manager="trManager"/>

    <!-- 事务处理:配置文件 
    <tx:advice id="aa" transaction-manager="trManager">
        <tx:attributes>
            <tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="update*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="delete*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut expression="execution(* com.itheima.elec.service..*.*(..))" id="bb"/>
        <aop:advisor advice-ref="aa" pointcut-ref="bb"/>
    </aop:config>
    -->
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 连接数据库的信息  这个配置在和spring整合之后是写在spring的配置文件中 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/项目名?useUnicode=true&amp;characterEncoding=utf8</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!-- 设置事务自动提交 
        <property name="hibernate.connection.autocommit">true</property>-->
        <!-- 其他配置 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>     
        <!-- 添加二级缓存 -->
        <!-- 1:开启二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!-- 2:要指定缓存的供应商(eache)的缓存 -->
        <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
        <!-- 4:在 hibernate 配置文件中启用查询缓存 -->
        <property name="hibernate.cache.use_query_cache">true</property>
        <!-- 添加映射 -->
        <mapping resource="com/itheima/elec/domain/ElecText.hbm.xml"/>
        <!-- 指定使用二级缓存的类 放在maping下面 -->
        <!-- 3:配置类级别的二级缓存 -->
        <class-cache usage="read-write" class="com.itheima.elec.domain.ElecSystemDDL"/>
    </session-factory>
</hibernate-configuration>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd 
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">

        <!-- 
            springmvc的注解驱动:<mvc:annotation-driven/>
            注解驱动的配置可以省去注解映射器和注解适配器的配置
            1.RequestMappingHandlerMapping
            2.RequestMappingHandlerAdapter
        -->
        <mvc:annotation-driven/>

        <!-- 
            注解扫描器:
            扫描controller注解,多个包中间使用半角逗号分隔 
            如果在spring的核心配置文件中已经配置了注解扫描,这里不用单独配置
        -->
        <context:component-scan base-package="com.metasoft.elec.web" />

        <!-- 
            id必须配,而且id的值是multipartResolver 
            value:按字节单位算
        -->
        <!-- <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize" value="102400000"></property>
        </bean> -->

        <!-- 
            配置视图解析器
            前缀:前后必须要有 /
            后缀: 必须要有.
         -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
            <property name="prefix" value="/WEB-INF/jsp/" />
            <property name="suffix" value=".jsp" />
        </bean>
</beans>

CommonDao和CommonDaoImpl代码

package com.metasoft.elec.dao.common;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * @Name: CommonDao.java
 * @Description: 公共Dao接口
 * @Author: zhaojd
 * @date: 2016年12月1日
 */
public interface CommonDao<T> {
    void save(T entity);
    void update(T entity);
    T getObjById(Serializable id);
    void deleteObjByIds(Serializable... ids);
    void deleteObjByCollection(List<T> list);
    List<?> findCollectionByConditionNoPage(String condition, Object[] params,
            Map<String, Object> orderby);
}
package com.metasoft.elec.utils;

import java.lang.reflect.ParameterizedType;

/**
 * 
 * @Name: TUtil.java 
 * @Description: T型转换
 * @Author: zhaojd
 * @date: 2016年12月1日
 */
public class TUtil {
    public static Class<?> getActualType(Class<?> entity) {
        ParameterizedType parameterizedType = (ParameterizedType) entity.getGenericSuperclass();
        Class<?> entityClass = (Class<?>) parameterizedType.getActualTypeArguments()[0];
        return entityClass;
    }
}
package com.metasoft.elec.dao.common.Impl;
import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import com.metasoft.elec.dao.common.CommonDao;
import com.metasoft.elec.utils.TUtil;
/**
 * @Name: CommonDaoImpl.java
 * @Description: 公共Dao接口实现类
 * @Author: zhaojd
 * @date: 2016年12月1日
 */
public class CommonDaoImpl<T> extends HibernateDaoSupport implements CommonDao<T> {

    /**
     * 泛型转换,获取真实对象的实体
     */
    Class<?> entityClass = TUtil.getActualType(this.getClass());

    //使用resource注入sessionFactory
    @Resource(name = "sessionFactory")
    public final void setSessionFactoryDi(SessionFactory sf) {
        this.setSessionFactory(sf);
    }

    public void save(T entity) {
        this.getHibernateTemplate().save(entity);
    }

    public void update(T entity) {
        this.getHibernateTemplate().update(entity);
    }

    @SuppressWarnings("unchecked")
    public T getObjById(Serializable id) {
        return (T) this.getHibernateTemplate().get(entityClass, id);
    }

    public void deleteObjByIds(Serializable... ids) {
        if (ids != null && ids.length > 0) {
            for (Serializable id : ids) {
                T entity = this.getObjById(id);
                this.getHibernateTemplate().delete(entity);
            }
        }
    }

    public void deleteObjByCollection(List<T> list) {
        this.getHibernateTemplate().deleteAll(list);
    }

    public List<?> findCollectionByConditionNoPage(String condition, final Object[] params,
            Map<String, Object> orderby) {
        String hql = "select e from " + entityClass.getSimpleName() + " e where 1 = 1";
        String orderByHql = this.initOrderByHql(orderby);
        final String finalHql = hql + condition + orderByHql;
        /**
         * 执行hql语句:
         *     方式一:直接使用hibernateTemplate的find()方法,find()方法支持执行hql语句
         *     方式二:获取sessionFactory,再获取session
         *     方式三:使用hibernateTemplate 调用回调函数
         */
        //List<?> list = this.getHibernateTemplate().find(finalHql, params);

        //        SessionFactory sf = this.getHibernateTemplate().getSessionFactory();
        //        Session session = sf.getCurrentSession();
        //        Query query = session.createQuery(finalHql);
        //        query.setParameter(0, params[0]);
        //        query.setParameter(1, params[1]);
        //        List<?> list = query.list();
        //        return list;

        List<?> list = (List<?>) this.getHibernateTemplate().execute(new HibernateCallback<Object>() {

            public Object doInHibernate(org.hibernate.Session session) throws HibernateException,
                    SQLException {
                Query query = session.createQuery(finalHql);
                if(params != null && params.length > 0){
                    for (int i = 0; i < params.length; i++) {
                        query.setParameter(0, params[i]);
                    }
                }
                return query.list();
            }
        });
        return list;
    }

    /**
     * 组织排序语句,将Map集合转换成String类型
     * @return
     */
    private String initOrderByHql(Map<String, Object> orderby) {
        StringBuffer stringBuffer = new StringBuffer();
        if (orderby != null && orderby.size() > 0) {
            stringBuffer.append(" order by ");
            for (Map.Entry<String, Object> map : orderby.entrySet()) {
                stringBuffer.append(map.getKey() + " " + map.getValue() + ",");
            }
            //删除最后一个逗号
            stringBuffer.deleteCharAt(stringBuffer.length() - 1);
        }
        return stringBuffer.toString();
    }
}
package com.metasoft.elec.junit;

import java.util.List;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.metasoft.elec.dao.ElecTestDao;
import com.metasoft.elec.domain.ElecTest;
public class TestDao {
    @SuppressWarnings({"resource", "unchecked"})
    @Test
    public void testSave() throws Exception {
        //加载类路径下的spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        ElecTestDao elecTestDao = (ElecTestDao) ac.getBean(ElecTestDao.BEAN_NAME);

        //        ElecTest elec = new ElecTest();
        //        elec.setDate(new Date());
        //        elec.setName("测试名称comm");
        //        elec.setRemark("备注");
        //        elecTestDao.save(elec);

        //        ElecTest elec_ = elecTestDao.getObjById("4028af8158b994f60158b994f8010000");
        //        elec_.setName("张三");
        //        elecTestDao.update(elec_);
作者:ZJDWHD 发表于2016/12/13 11:49:15 原文链接
阅读:32 评论:0 查看评论

使用HTML5 Canvas创建动态粒子网格动画

$
0
0

最近看到一个粒子网格动画挺炫的,自己也就做了一个,当背景挺不错的。CSDN不能上传超过2M的图片,所以就简单截了一个静态图片:

粒子网格

可以点击这里查看动画.

下面就开始说怎么实现这个效果吧:
首先当然是添加一个canvas了:

<canvas id="canvas"></canvas>

下面是样式:

<style>
    #canvas{
        position: absolute;
        display: block;
        left:0;
        top:0;
        background: #0f0f0f;
        z-index: -1;
     }
</style>

上面canvasz-index: -1的作用是可以放在一些元素的下面当做背景。

为了确保canvas能够充满整个浏览器,所以要将canvas的宽高设置成和浏览器一样:

function getSize(){
    w = canvas.width = window.innerWidth;
    h = canvas.height = window.innerHeight;
}

上面wh分别代表浏览器的宽高。

获得了浏览器的宽高,接下来就是在里面画粒子了,这里我们需要提前定义一些粒子的参数:

var opt = {
    particleAmount: 50,         //粒子个数
    defaultSpeed: 1,            //粒子运动速度
    variantSpeed: 1,            //粒子运动速度的变量
    particleColor: "rgb(32,245,245)",       //粒子的颜色
    lineColor:"rgb(32,245,245)",            //网格连线的颜色
    defaultRadius: 2,           //粒子半径
    variantRadius: 2,           //粒子半径的变量
    minDistance: 200            //粒子之间连线的最小距离
};

上面的速度变量和半径变量都是为了保证粒子的大小和速度不是一模一样。

然后我们再创建一个类用来初始化粒子,代码比较长,我都加了注释:

function Partical(){
    this.x = Math.random()*w;           //粒子的x轴坐标
    this.y = Math.random()*h;           //粒子的y轴坐标
    this.speed = opt.defaultSpeed + opt.variantSpeed*Math.random();     //粒子的运动速度
    this.directionAngle = Math.floor(Math.random()*360);                //粒子运动的方向
    this.color = opt.particleColor ;                                    //粒子的颜色
    this.radius = opt.defaultRadius+Math.random()*opt.variantRadius;    //粒子的半径大小
    this.vector = {
        x:this.speed * Math.cos(this.directionAngle),       //粒子在x轴的速度
        y:this.speed * Math.sin(this.directionAngle)        //粒子在y轴的速度
    }
    this.update = function(){                   //粒子的更新函数
        this.border();                           //判断粒子是否到了边界
        this.x += this.vector.x;                //粒子下一时刻在x轴的坐标
        this.y += this.vector.y;                //粒子下一时刻在y轴的坐标
    }
    this.border = function(){               //判断粒子是都到达边界
        if(this.x >= w || this.x<= 0){      //如果到达左右边界,就让x轴的速度变为原来的负数
            this.vector.x *= -1;
        }
        if(this.y >= h || this.y <= 0){     //如果到达上下边界,就让y轴的速度变为原来的负数
            this.vector.y *= -1;
        }
        if(this.x > w){                     //下面是改变浏览器窗口大小时的操作,改变窗口大小后有的粒子会被隐藏,让他显示出来即可
            this.x = w;
        }
        if(this.y > h){
            this.y = h;
        }
        if(this.x < 0){
            this.x = 0;
        }
        if(this.y < 0){
            this.y = 0;
        }
    }
    this.draw = function(){                 //绘制粒子的函数
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius ,0 ,Math.PI * 2);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}
  1. 每个粒子的初始速度和角度是随机生成的,粒子的颜色通过相关的设置选项来确定。

  2. this.vector用来存储粒子的移动方向:如果this.vector.x为1,则粒子向右运动;如果是-1,则粒子向左移动。同样,如果this.vector.y为负,则粒子向上移动,如果为正,则粒子向下移动。
    this.update用来更新每个粒子下一个位置的坐标。首先,进行边缘检测;如果粒子的移动超出了canvas的尺寸,则将方向向量乘以-1产生反向的运动方向。

  3. 窗口缩放可能会引起粒子超出边界,如此一来边缘检测函数就捕捉不到了,所以就需要一系列的if语句来检测这种情况,将粒子的位置重置为当前canvas的边界。

  4. 最后一步,将这些点绘制到画布上。

粒子的类已经写好了,下面就把他绘制出来:

function init(){
   getSize();
   for(let i = 0;i<opt.particleAmount; i++){
        particle.push(new Partical());
   }
   loop();
}

上面初始化了opt.particleAmount个粒子对象,初始化了对象但是并没有绘制出来,下面是loop函数:

function loop(){
    ctx.clearRect(0,0,w,h);
    for(let i = 0;i<particle.length; i++){
        particle[i].update();
        particle[i].draw();
    }
    window.requestAnimationFrame(loop);
}

loop()函数每执行一次,都会清除canvas上的内容,然后通过粒子对象的update()函数重新计算粒子的坐标,最后通过粒子对象的draw()函数来绘制粒子。下面是这个时候的效果:

粒子动画

但是在浏览器窗口大小改变以后有些粒子就会消失不见,这个时候需要添加一个事件来监听浏览器大小是否改变:

window.addEventListener("resize",function(){
    winResize()
},false);

然后需要来写winResize()函数,这里需要注意一下,浏览器改变的时候触发resize事件的次数会特别频繁,稍微移动一下浏览器的边缘就是触发几十次resize事件,那么也就会重新计算几十次浏览器大小,比较消耗性能,这个大家可以测试一下,这里就直接说解决方法吧,其实我们要的只是浏览器改变后的最后的大小,至于中间到底改变了多少次和我们没有关系,所以我们可以在浏览器窗口改变的时候延缓200毫秒后执行计算浏览器大小的事件,如果在这期间一直触发resize事件,那就一直往后延缓200毫秒,听起来挺复杂,其实代码很简单:

var particle = [], w,h;     //粒子数组,浏览器宽高
var delay = 200,tid;        //延缓执行事件和setTimeout事件引用
function winResize(){
    clearTimeout(tid);
    tid = setTimeout(function(){
        getSize();          //获取浏览器宽高,在文章最上面有介绍
    },delay)
}

这样所有的粒子动画都完成了,接下来就可以在粒子之间画线了,我们上面定义的opt对象里面有一个minDistance变量,当两个粒子之间的连线小于这个值的时候,我们就给他们之间画上线。

那么如何计算两个粒子之间的距离呢,大家可以回想一下初中数学第一课,勾股定理,直角三角形两个直角边的平方和等于第三条变的平方,看下面:
勾股定理

我们现在知道每个粒子的x轴和y轴的坐标,那么我们就可以计算出两个点之间的距离了,写一个函数,传入两个点,如下:

function getDistance(point1,point2){
        return Math.sqrt(Math.pow(point1.x-point2.x,2) + Math.pow(point1.y - point2.y ,2));
    }

现在我们可以计算出两个点的距离,那么我们就计算出所有每个粒子同其他所有粒子的距离,来确定它们之间是否需要连线,当然如果所有粒子的颜色深度都一模一样,那就有点丑了,所以我们这里可以根据两个粒子之间的距离来决定连线的透明度,两个粒子距离越近,越不透明,距离越远,越透明,超过一定距离就不显示了。

function linePoint(point,hub){
    for(let i = 0;i<hub.length;i++){
        let distance = getDistance(point,hub[i]);
        let opacity = 1 -distance/opt.minDistance;
        if(opacity > 0){
            ctx.lineWidth = 0.5;
            ctx.strokeStyle = "rgba("+line[0]+","+line[1]+","+line[2]+","+opacity+")";
            ctx.beginPath();
            ctx.moveTo(point.x,point.y);
            ctx.lineTo(hub[i].x,hub[i].y);
            ctx.closePath();
            ctx.stroke();
        }
    }
}

上面传入的两个参数分别是一个点和整个点的数组,let opacity = 1 -distance/opt.minDistance;用于判断连线之间的透明度同时也判断了距离,距离大于opt.minDistance时,opacity为负,下面判断时就过滤掉了,上面的颜色用到了正则表达式,需要先解析最上面opt对象里给出的颜色,然后再加上透明度,这段代码如下:

var line = opt.lineColor.match(/\d+/g);

最后在loop()函数里面不断循环计算距离就可以了,在loop()中加入代码后如下:

function loop(){
        ctx.clearRect(0,0,w,h);
        for(let i = 0;i<particle.length; i++){
            particle[i].update();
            particle[i].draw();
        }
        for(let i = 0;i<particle.length; i++){   //添加的是这个循环
            linePoint(particle[i],particle)
        }
        window.requestAnimationFrame(loop);
    }

需要指出的是:如果添加过多的点和/或过多的连接距离(连接距离会创建过多的线条),动画也会扛不住。当视口变窄时最好降低粒子的运动速度:粒子的尺寸越小,在愈加狭窄空间内的移动速度貌似会越快。

显示整段代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>canvas粒子动画</title>
    <style>
        #canvas{
            position: absolute;
            display: block;
            left:0;
            top:0;
            background: #0f0f0f;
            z-index: -1;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var opt = {
        particleAmount: 50,     //粒子个数
        defaultSpeed: 1,        //粒子运动速度
        variantSpeed: 1,        //粒子运动速度的变量
        particleColor: "rgb(32,245,245)",       //粒子的颜色
        lineColor:"rgb(32,245,245)",            //网格连线的颜色
        defaultRadius: 2,           //粒子半径
        variantRadius: 2,           //粒子半径的变量
        minDistance: 200            //粒子之间连线的最小距离
    };
    var line = opt.lineColor.match(/\d+/g);
    console.log(line);
    var particle = [], w,h;
    var delay = 200,tid;
    init();
    window.addEventListener("resize",function(){
        winResize()
    },false);

    function winResize(){
        clearTimeout(tid);
        tid = setTimeout(function(){
            getSize();
        },delay)
    }

    function init(){
        getSize();
        for(let i = 0;i<opt.particleAmount; i++){
            particle.push(new Partical());
        }
        loop();
    }

    function loop(){
        ctx.clearRect(0,0,w,h);
        for(let i = 0;i<particle.length; i++){
            particle[i].update();
            particle[i].draw();
        }
        for(let i = 0;i<particle.length; i++){
            linePoint(particle[i],particle)
        }
        window.requestAnimationFrame(loop);
    }

    function linePoint(point,hub){
        for(let i = 0;i<hub.length;i++){
            let distance = getDistance(point,hub[i]);
            let opacity = 1 -distance/opt.minDistance;
            if(opacity > 0){
                ctx.lineWidth = 0.5;
                ctx.strokeStyle = "rgba("+line[0]+","+line[1]+","+line[2]+","+opacity+")";
                ctx.beginPath();
                ctx.moveTo(point.x,point.y);
                ctx.lineTo(hub[i].x,hub[i].y);
                ctx.closePath();
                ctx.stroke();
            }
        }
    }

    function getDistance(point1,point2){
        return Math.sqrt(Math.pow(point1.x-point2.x,2) + Math.pow(point1.y - point2.y ,2));
    }

    function getSize(){
        w = canvas.width = window.innerWidth;
        h = canvas.height = window.innerHeight;
    }
    function Partical(){
        this.x = Math.random()*w;           //粒子的x轴坐标
        this.y = Math.random()*h;           //粒子的y轴坐标
        this.speed = opt.defaultSpeed + opt.variantSpeed*Math.random();     //粒子的运动速度
        this.directionAngle = Math.floor(Math.random()*360);                //粒子运动的方向
        this.color = opt.particleColor ;                                    //粒子的颜色
        this.radius = opt.defaultRadius+Math.random()*opt.variantRadius;    //粒子的半径大小
        this.vector = {
            x:this.speed * Math.cos(this.directionAngle),       //粒子在x轴的速度
            y:this.speed * Math.sin(this.directionAngle)        //粒子在y轴的速度
        }
        this.update = function(){                   //粒子的更新函数
            this.border();                           //判断粒子是否到了边界
            this.x += this.vector.x;                //粒子下一时刻在x轴的坐标
            this.y += this.vector.y;                //粒子下一时刻在y轴的坐标
        }
        this.border = function(){               //判断粒子是都到达边界
            if(this.x >= w || this.x<= 0){      //如果到达左右边界,就让x轴的速度变为原来的负数
                this.vector.x *= -1;
            }
            if(this.y >= h || this.y <= 0){     //如果到达上下边界,就让y轴的速度变为原来的负数
                this.vector.y *= -1;
            }
            if(this.x > w){                     //下面是改变浏览器窗口大小时的操作,改变窗口大小后有的粒子会被隐藏,让他显示出来即可
                this.x = w;
            }
            if(this.y > h){
                this.y = h;
            }
            if(this.x < 0){
                this.x = 0;
            }
            if(this.y < 0){
                this.y = 0;
            }
        }
        this.draw = function(){                 //绘制粒子的函数
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.radius ,0 ,Math.PI * 2);
            ctx.closePath();
            ctx.fillStyle = this.color;
            ctx.fill();
        }
    }
</script>
</body>
</html>
作者:u014346301 发表于2016/12/13 11:50:20 原文链接
阅读:563 评论:3 查看评论

make menuconfig出现一大堆未定义的错误

$
0
0


kernel$ make menuconfig
  HOSTLD  scripts/kconfig/mconf
scripts/kconfig/mconf.o:在函数‘show_help’中:
mconf.c:(.text+0x914):对‘stdscr’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘print_arrows’中:
checklist.c:(.text+0x2c):对‘wmove’未定义的引用
checklist.c:(.text+0x4c):对‘acs_map’未定义的引用
checklist.c:(.text+0x54):对‘waddch’未定义的引用
checklist.c:(.text+0x66):对‘waddnstr’未定义的引用
checklist.c:(.text+0x76):对‘wmove’未定义的引用
checklist.c:(.text+0x9f):对‘acs_map’未定义的引用
checklist.c:(.text+0xa7):对‘waddch’未定义的引用
checklist.c:(.text+0xe3):对‘acs_map’未定义的引用
checklist.c:(.text+0xeb):对‘waddch’未定义的引用
checklist.c:(.text+0xf2):对‘acs_map’未定义的引用
checklist.c:(.text+0xfa):对‘waddch’未定义的引用
checklist.c:(.text+0x101):对‘acs_map’未定义的引用
checklist.c:(.text+0x109):对‘waddch’未定义的引用
checklist.c:(.text+0x110):对‘acs_map’未定义的引用
checklist.c:(.text+0x143):对‘acs_map’未定义的引用
checklist.c:(.text+0x14b):对‘waddch’未定义的引用
checklist.c:(.text+0x152):对‘acs_map’未定义的引用
checklist.c:(.text+0x15a):对‘waddch’未定义的引用
checklist.c:(.text+0x161):对‘acs_map’未定义的引用
checklist.c:(.text+0x169):对‘waddch’未定义的引用
checklist.c:(.text+0x170):对‘acs_map’未定义的引用
checklist.c:(.text+0x178):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘print_item’中:
checklist.c:(.text+0x201):对‘wmove’未定义的引用
checklist.c:(.text+0x224):对‘waddch’未定义的引用
checklist.c:(.text+0x23d):对‘wmove’未定义的引用
checklist.c:(.text+0x288):对‘wmove’未定义的引用
checklist.c:(.text+0x2ae):对‘waddnstr’未定义的引用
checklist.c:(.text+0x2c7):对‘wmove’未定义的引用
checklist.c:(.text+0x2cf):对‘wrefresh’未定义的引用
checklist.c:(.text+0x321):对‘wprintw’未定义的引用
checklist.c:(.text+0x34f):对‘wmove’未定义的引用
checklist.c:(.text+0x361):对‘waddch’未定义的引用
checklist.c:(.text+0x388):对‘wmove’未定义的引用
checklist.c:(.text+0x3a6):对‘wmove’未定义的引用
checklist.c:(.text+0x3c8):对‘wmove’未定义的引用
checklist.c:(.text+0x3dd):对‘waddch’未定义的引用
checklist.c:(.text+0x3f3):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘print_buttons’中:
checklist.c:(.text+0x481):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘dialog_checklist’中:
checklist.c:(.text+0x5a5):对‘stdscr’未定义的引用
checklist.c:(.text+0x5ee):对‘stdscr’未定义的引用
checklist.c:(.text+0x646):对‘newwin’未定义的引用
checklist.c:(.text+0x65b):对‘keypad’未定义的引用
checklist.c:(.text+0x6a3):对‘wmove’未定义的引用
checklist.c:(.text+0x6af):对‘acs_map’未定义的引用
checklist.c:(.text+0x6b7):对‘waddch’未定义的引用
checklist.c:(.text+0x6db):对‘acs_map’未定义的引用
checklist.c:(.text+0x6e7):对‘waddch’未定义的引用
checklist.c:(.text+0x70f):对‘acs_map’未定义的引用
checklist.c:(.text+0x717):对‘waddch’未定义的引用
checklist.c:(.text+0x77d):对‘subwin’未定义的引用
checklist.c:(.text+0x78f):对‘keypad’未定义的引用
checklist.c:(.text+0x923):对‘wnoutrefresh’未定义的引用
checklist.c:(.text+0x92d):对‘wnoutrefresh’未定义的引用
checklist.c:(.text+0x932):对‘doupdate’未定义的引用
checklist.c:(.text+0x94e):对‘wgetch’未定义的引用
checklist.c:(.text+0xa6d):对‘wnoutrefresh’未定义的引用
checklist.c:(.text+0xa75):对‘wrefresh’未定义的引用
checklist.c:(.text+0xa8e):对‘delwin’未定义的引用
checklist.c:(.text+0xa98):对‘delwin’未定义的引用
checklist.c:(.text+0xb3d):对‘delwin’未定义的引用
checklist.c:(.text+0xb47):对‘delwin’未定义的引用
checklist.c:(.text+0xb53):对‘stdscr’未定义的引用
checklist.c:(.text+0xbbe):对‘scrollok’未定义的引用
checklist.c:(.text+0xbcb):对‘wscrl’未定义的引用
checklist.c:(.text+0xbd5):对‘scrollok’未定义的引用
checklist.c:(.text+0xc30):对‘wnoutrefresh’未定义的引用
checklist.c:(.text+0xc38):对‘wrefresh’未定义的引用
checklist.c:(.text+0xcb2):对‘scrollok’未定义的引用
checklist.c:(.text+0xcbf):对‘wscrl’未定义的引用
checklist.c:(.text+0xcc9):对‘scrollok’未定义的引用
checklist.c:(.text+0xd2e):对‘wnoutrefresh’未定义的引用
checklist.c:(.text+0xd36):对‘wrefresh’未定义的引用
checklist.c:(.text+0xd90):对‘wrefresh’未定义的引用
checklist.c:(.text+0xd95):对‘doupdate’未定义的引用
checklist.c:(.text+0xdc1):对‘doupdate’未定义的引用
checklist.c:(.text+0xe3d):对‘delwin’未定义的引用
checklist.c:(.text+0xe47):对‘delwin’未定义的引用
checklist.c:(.text+0xe82):对‘doupdate’未定义的引用
checklist.c:(.text+0xe93):对‘stdscr’未定义的引用
checklist.c:(.text+0xec5):对‘doupdate’未定义的引用
checklist.c:(.text+0xedd):对‘doupdate’未定义的引用
checklist.c:(.text+0xef2):对‘acs_map’未定义的引用
checklist.c:(.text+0xef9):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘print_arrows’中:
checklist.c:(.text+0xc7):对‘waddnstr’未定义的引用
checklist.c:(.text+0x126):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/checklist.o:在函数‘print_buttons’中:
checklist.c:(.text+0x493):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘init_one_color’中:
util.c:(.text+0x46f):对‘init_pair’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘attr_clear’中:
util.c:(.text+0x4d1):对‘wmove’未定义的引用
util.c:(.text+0x4ec):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘dialog_clear’中:
util.c:(.text+0x541):对‘stdscr’未定义的引用
util.c:(.text+0x57e):对‘stdscr’未定义的引用
util.c:(.text+0x59a):对‘wmove’未定义的引用
util.c:(.text+0x5ad):对‘stdscr’未定义的引用
util.c:(.text+0x5b7):对‘waddnstr’未定义的引用
util.c:(.text+0x5ec):对‘stdscr’未定义的引用
util.c:(.text+0x5ff):对‘wmove’未定义的引用
util.c:(.text+0x655):对‘acs_map’未定义的引用
util.c:(.text+0x65c):对‘stdscr’未定义的引用
util.c:(.text+0x661):对‘waddch’未定义的引用
util.c:(.text+0x668):对‘stdscr’未定义的引用
util.c:(.text+0x677):对‘waddch’未定义的引用
util.c:(.text+0x683):对‘stdscr’未定义的引用
util.c:(.text+0x691):对‘waddnstr’未定义的引用
util.c:(.text+0x698):对‘stdscr’未定义的引用
util.c:(.text+0x6a2):对‘waddch’未定义的引用
util.c:(.text+0x6c3):对‘acs_map’未定义的引用
util.c:(.text+0x6ca):对‘stdscr’未定义的引用
util.c:(.text+0x6d3):对‘waddch’未定义的引用
util.c:(.text+0x6df):对‘stdscr’未定义的引用
util.c:(.text+0x703):对‘stdscr’未定义的引用
util.c:(.text+0x715):对‘waddnstr’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘init_dialog’中:
util.c:(.text+0x755):对‘initscr’未定义的引用
util.c:(.text+0x75c):对‘stdscr’未定义的引用
util.c:(.text+0x942):对‘stdscr’未定义的引用
util.c:(.text+0x94c):对‘keypad’未定义的引用
util.c:(.text+0x951):对‘cbreak’未定义的引用
util.c:(.text+0x956):对‘noecho’未定义的引用
util.c:(.text+0xccf):对‘has_colors’未定义的引用
util.c:(.text+0xcdc):对‘start_color’未定义的引用
util.c:(.text+0xe16):对‘has_colors’未定义的引用
util.c:(.text+0xe36):对‘has_colors’未定义的引用
util.c:(.text+0xe65):对‘endwin’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘end_dialog’中:
util.c:(.text+0xe99):对‘stdscr’未定义的引用
util.c:(.text+0xe9e):对‘wmove’未定义的引用
util.c:(.text+0xea5):对‘stdscr’未定义的引用
util.c:(.text+0xeaa):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘print_title’中:
util.c:(.text+0xf16):对‘wmove’未定义的引用
util.c:(.text+0xf28):对‘waddch’未定义的引用
util.c:(.text+0xf34):对‘wmove’未定义的引用
util.c:(.text+0xf47):对‘waddnstr’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘print_autowrap’中:
util.c:(.text+0x1041):对‘wmove’未定义的引用
util.c:(.text+0x1051):对‘waddnstr’未定义的引用
util.c:(.text+0x11b7):对‘wmove’未定义的引用
util.c:(.text+0x11c7):对‘waddnstr’未定义的引用
util.c:(.text+0x121d):对‘wmove’未定义的引用
util.c:(.text+0x122d):对‘waddnstr’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘print_button’中:
util.c:(.text+0x1265):对‘wmove’未定义的引用
util.c:(.text+0x1292):对‘waddnstr’未定义的引用
util.c:(.text+0x12f5):对‘waddch’未定义的引用
util.c:(.text+0x1324):对‘waddch’未定义的引用
util.c:(.text+0x1340):对‘waddnstr’未定义的引用
util.c:(.text+0x135d):对‘waddnstr’未定义的引用
util.c:(.text+0x13b4):对‘waddch’未定义的引用
util.c:(.text+0x13d0):对‘waddnstr’未定义的引用
util.c:(.text+0x13f8):对‘waddch’未定义的引用
util.c:(.text+0x1408):对‘waddnstr’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘draw_box’中:
util.c:(.text+0x1499):对‘wmove’未定义的引用
util.c:(.text+0x14df):对‘waddch’未定义的引用
util.c:(.text+0x14fc):对‘acs_map’未定义的引用
util.c:(.text+0x1508):对‘waddch’未定义的引用
util.c:(.text+0x154d):对‘acs_map’未定义的引用
util.c:(.text+0x1555):对‘waddch’未定义的引用
util.c:(.text+0x1568):对‘acs_map’未定义的引用
util.c:(.text+0x1570):对‘waddch’未定义的引用
util.c:(.text+0x1583):对‘acs_map’未定义的引用
util.c:(.text+0x158b):对‘waddch’未定义的引用
util.c:(.text+0x15a1):对‘acs_map’未定义的引用
util.c:(.text+0x15a9):对‘waddch’未定义的引用
util.c:(.text+0x15ba):对‘acs_map’未定义的引用
util.c:(.text+0x15c2):对‘waddch’未定义的引用
util.c:(.text+0x15d3):对‘acs_map’未定义的引用
util.c:(.text+0x15db):对‘waddch’未定义的引用
util.c:(.text+0x15ec):对‘acs_map’未定义的引用
util.c:(.text+0x15f4):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘draw_shadow’中:
util.c:(.text+0x161d):对‘has_colors’未定义的引用
util.c:(.text+0x164a):对‘wmove’未定义的引用
util.c:(.text+0x1660):对‘winch’未定义的引用
util.c:(.text+0x166b):对‘waddch’未定义的引用
util.c:(.text+0x1689):对‘wmove’未定义的引用
util.c:(.text+0x1694):对‘winch’未定义的引用
util.c:(.text+0x169f):对‘waddch’未定义的引用
util.c:(.text+0x16a7):对‘winch’未定义的引用
util.c:(.text+0x16b2):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘on_key_esc’中:
util.c:(.text+0x17ed):对‘nodelay’未定义的引用
util.c:(.text+0x17f7):对‘keypad’未定义的引用
util.c:(.text+0x17ff):对‘wgetch’未定义的引用
util.c:(.text+0x1809):对‘wgetch’未定义的引用
util.c:(.text+0x1814):对‘wgetch’未定义的引用
util.c:(.text+0x1823):对‘nodelay’未定义的引用
util.c:(.text+0x1830):对‘keypad’未定义的引用
util.c:(.text+0x186c):对‘ungetch’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘attr_clear’中:
util.c:(.text+0x51d):对‘wtouchln’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘dialog_clear’中:
util.c:(.text+0x6f2):对‘wnoutrefresh’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘end_dialog’中:
util.c:(.text+0xeb3):对‘endwin’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘print_title’中:
util.c:(.text+0xf5e):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘print_button’中:
util.c:(.text+0x137c):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/util.o:在函数‘draw_shadow’中:
util.c:(.text+0x16cd):对‘wnoutrefresh’未定义的引用
scripts/kconfig/lxdialog/inputbox.o:在函数‘print_buttons’中:
inputbox.c:(.text+0x81):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/inputbox.o:在函数‘dialog_inputbox’中:
inputbox.c:(.text+0xdd):对‘stdscr’未定义的引用
inputbox.c:(.text+0x17d):对‘newwin’未定义的引用
inputbox.c:(.text+0x18d):对‘keypad’未定义的引用
inputbox.c:(.text+0x1d0):对‘wmove’未定义的引用
inputbox.c:(.text+0x1dc):对‘acs_map’未定义的引用
inputbox.c:(.text+0x1e4):对‘waddch’未定义的引用
inputbox.c:(.text+0x1fb):对‘acs_map’未定义的引用
inputbox.c:(.text+0x207):对‘waddch’未定义的引用
inputbox.c:(.text+0x22a):对‘acs_map’未定义的引用
inputbox.c:(.text+0x22f):对‘waddch’未定义的引用
inputbox.c:(.text+0x2c4):对‘wmove’未定义的引用
inputbox.c:(.text+0x35c):对‘waddch’未定义的引用
inputbox.c:(.text+0x370):对‘wmove’未定义的引用
inputbox.c:(.text+0x378):对‘wrefresh’未定义的引用
inputbox.c:(.text+0x3ab):对‘wgetch’未定义的引用
inputbox.c:(.text+0x40b):对‘delwin’未定义的引用
inputbox.c:(.text+0x429):对‘waddch’未定义的引用
inputbox.c:(.text+0x439):对‘wmove’未定义的引用
inputbox.c:(.text+0x441):对‘wrefresh’未定义的引用
inputbox.c:(.text+0x449):对‘wgetch’未定义的引用
inputbox.c:(.text+0x4e2):对‘wgetch’未定义的引用
inputbox.c:(.text+0x583):对‘wmove’未定义的引用
inputbox.c:(.text+0x5dd):对‘waddch’未定义的引用
inputbox.c:(.text+0x634):对‘delwin’未定义的引用
inputbox.c:(.text+0x64e):对‘waddnstr’未定义的引用
inputbox.c:(.text+0x684):对‘delwin’未定义的引用
inputbox.c:(.text+0x6cf):对‘delwin’未定义的引用
inputbox.c:(.text+0x6db):对‘stdscr’未定义的引用
inputbox.c:(.text+0x75f):对‘wgetch’未定义的引用
inputbox.c:(.text+0x7a9):对‘wmove’未定义的引用
inputbox.c:(.text+0x7b6):对‘wgetch’未定义的引用
inputbox.c:(.text+0x892):对‘wgetch’未定义的引用
inputbox.c:(.text+0x930):对‘wgetch’未定义的引用
inputbox.c:(.text+0x99a):对‘wmove’未定义的引用
inputbox.c:(.text+0x9a2):对‘wrefresh’未定义的引用
inputbox.c:(.text+0x9b4):对‘wgetch’未定义的引用
inputbox.c:(.text+0xaa4):对‘wmove’未定义的引用
inputbox.c:(.text+0xaf6):对‘waddch’未定义的引用
inputbox.c:(.text+0xb0a):对‘wmove’未定义的引用
inputbox.c:(.text+0xb12):对‘wrefresh’未定义的引用
inputbox.c:(.text+0xb24):对‘wgetch’未定义的引用
inputbox.c:(.text+0xba5):对‘wgetch’未定义的引用
inputbox.c:(.text+0xc08):对‘wgetch’未定义的引用
inputbox.c:(.text+0xc5c):对‘wgetch’未定义的引用
inputbox.c:(.text+0xcb3):对‘acs_map’未定义的引用
inputbox.c:(.text+0xcba):对‘waddch’未定义的引用
inputbox.c:(.text+0xd33):对‘wmove’未定义的引用
inputbox.c:(.text+0xd4a):对‘wgetch’未定义的引用
inputbox.c:(.text+0xdc6):对‘wmove’未定义的引用
inputbox.c:(.text+0xdce):对‘wrefresh’未定义的引用
inputbox.c:(.text+0xde0):对‘wgetch’未定义的引用
inputbox.c:(.text+0xf26):对‘wgetch’未定义的引用
inputbox.c:(.text+0xfa9):对‘delwin’未定义的引用
inputbox.c:(.text+0xfe8):对‘wmove’未定义的引用
inputbox.c:(.text+0x1039):对‘waddch’未定义的引用
inputbox.c:(.text+0x104f):对‘wmove’未定义的引用
inputbox.c:(.text+0x116b):对‘flash’未定义的引用
inputbox.c:(.text+0x117d):对‘wgetch’未定义的引用
inputbox.c:(.text+0x161a):对‘wmove’未定义的引用
inputbox.c:(.text+0x169d):对‘waddch’未定义的引用
inputbox.c:(.text+0x174f):对‘waddch’未定义的引用
inputbox.c:(.text+0x17a6):对‘wmove’未定义的引用
inputbox.c:(.text+0x17ed):对‘waddch’未定义的引用
inputbox.c:(.text+0x1801):对‘wmove’未定义的引用
inputbox.c:(.text+0x1836):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/inputbox.o:在函数‘print_buttons’中:
inputbox.c:(.text+0x93):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/textbox.o:在函数‘refresh_text_box’中:
textbox.c:(.text+0x26a):对‘wmove’未定义的引用
textbox.c:(.text+0x277):对‘waddch’未定义的引用
textbox.c:(.text+0x295):对‘waddnstr’未定义的引用
textbox.c:(.text+0x29d):对‘wclrtoeol’未定义的引用
textbox.c:(.text+0x2cf):对‘wnoutrefresh’未定义的引用
textbox.c:(.text+0x2f9):对‘wbkgdset’未定义的引用
textbox.c:(.text+0x346):对‘wmove’未定义的引用
textbox.c:(.text+0x357):对‘wprintw’未定义的引用
textbox.c:(.text+0x367):对‘wmove’未定义的引用
textbox.c:(.text+0x398):对‘wbkgdset’未定义的引用
scripts/kconfig/lxdialog/textbox.o:在函数‘dialog_textbox’中:
textbox.c:(.text+0x460):对‘stdscr’未定义的引用
textbox.c:(.text+0x4fd):对‘newwin’未定义的引用
textbox.c:(.text+0x50d):对‘keypad’未定义的引用
textbox.c:(.text+0x528):对‘subwin’未定义的引用
textbox.c:(.text+0x549):对‘wbkgdset’未定义的引用
textbox.c:(.text+0x556):对‘keypad’未定义的引用
textbox.c:(.text+0x59b):对‘wmove’未定义的引用
textbox.c:(.text+0x5a7):对‘acs_map’未定义的引用
textbox.c:(.text+0x5af):对‘waddch’未定义的引用
textbox.c:(.text+0x5c3):对‘acs_map’未定义的引用
textbox.c:(.text+0x5ce):对‘waddch’未定义的引用
textbox.c:(.text+0x5f4):对‘wbkgdset’未定义的引用
textbox.c:(.text+0x5fb):对‘acs_map’未定义的引用
textbox.c:(.text+0x603):对‘waddch’未定义的引用
textbox.c:(.text+0x64f):对‘wnoutrefresh’未定义的引用
textbox.c:(.text+0x69f):对‘wgetch’未定义的引用
textbox.c:(.text+0x709):对‘delwin’未定义的引用
textbox.c:(.text+0x711):对‘delwin’未定义的引用
textbox.c:(.text+0x71d):对‘stdscr’未定义的引用
textbox.c:(.text+0x81e):对‘delwin’未定义的引用
textbox.c:(.text+0x826):对‘delwin’未定义的引用
textbox.c:(.text+0xb35):对‘wbkgdset’未定义的引用
textbox.c:(.text+0xb3c):对‘acs_map’未定义的引用
textbox.c:(.text+0xb43):对‘waddch’未定义的引用
textbox.c:(.text+0xb92):对‘wnoutrefresh’未定义的引用
scripts/kconfig/lxdialog/textbox.o:在函数‘refresh_text_box’中:
textbox.c:(.text+0x37d):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/yesno.o:在函数‘print_buttons’中:
yesno.c:(.text+0x85):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/yesno.o:在函数‘dialog_yesno’中:
yesno.c:(.text+0xcd):对‘stdscr’未定义的引用
yesno.c:(.text+0x155):对‘newwin’未定义的引用
yesno.c:(.text+0x165):对‘keypad’未定义的引用
yesno.c:(.text+0x1a8):对‘wmove’未定义的引用
yesno.c:(.text+0x1b4):对‘acs_map’未定义的引用
yesno.c:(.text+0x1bc):对‘waddch’未定义的引用
yesno.c:(.text+0x1d3):对‘acs_map’未定义的引用
yesno.c:(.text+0x1df):对‘waddch’未定义的引用
yesno.c:(.text+0x202):对‘acs_map’未定义的引用
yesno.c:(.text+0x207):对‘waddch’未定义的引用
yesno.c:(.text+0x257):对‘wgetch’未定义的引用
yesno.c:(.text+0x282):对‘delwin’未定义的引用
yesno.c:(.text+0x2c0):对‘delwin’未定义的引用
yesno.c:(.text+0x2e6):对‘delwin’未定义的引用
yesno.c:(.text+0x32e):对‘wrefresh’未定义的引用
yesno.c:(.text+0x345):对‘delwin’未定义的引用
yesno.c:(.text+0x363):对‘delwin’未定义的引用
yesno.c:(.text+0x36f):对‘stdscr’未定义的引用
yesno.c:(.text+0x3d3):对‘acs_map’未定义的引用
yesno.c:(.text+0x3da):对‘waddch’未定义的引用
scripts/kconfig/lxdialog/yesno.o:在函数‘print_buttons’中:
yesno.c:(.text+0x97):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘do_scroll’中:
menubox.c:(.text+0x13):对‘scrollok’未定义的引用
menubox.c:(.text+0x1e):对‘wscrl’未定义的引用
menubox.c:(.text+0x28):对‘scrollok’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘do_print_item’中:
menubox.c:(.text+0xbe):对‘wmove’未定义的引用
menubox.c:(.text+0xc6):对‘wclrtoeol’未定义的引用
menubox.c:(.text+0xed):对‘wmove’未定义的引用
menubox.c:(.text+0x102):对‘waddnstr’未定义的引用
menubox.c:(.text+0x135):对‘wmove’未定义的引用
menubox.c:(.text+0x147):对‘waddch’未定义的引用
menubox.c:(.text+0x160):对‘wmove’未定义的引用
menubox.c:(.text+0x190):对‘wmove’未定义的引用
menubox.c:(.text+0x197):对‘wclrtoeol’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘print_buttons’中:
menubox.c:(.text+0x2a6):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘print_arrows.constprop.0’中:
menubox.c:(.text+0x2f9):对‘wmove’未定义的引用
menubox.c:(.text+0x313):对‘acs_map’未定义的引用
menubox.c:(.text+0x31b):对‘waddch’未定义的引用
menubox.c:(.text+0x32d):对‘waddnstr’未定义的引用
menubox.c:(.text+0x33d):对‘wmove’未定义的引用
menubox.c:(.text+0x345):对‘wrefresh’未定义的引用
menubox.c:(.text+0x369):对‘acs_map’未定义的引用
menubox.c:(.text+0x371):对‘waddch’未定义的引用
menubox.c:(.text+0x378):对‘acs_map’未定义的引用
menubox.c:(.text+0x380):对‘waddch’未定义的引用
menubox.c:(.text+0x387):对‘acs_map’未定义的引用
menubox.c:(.text+0x38f):对‘waddch’未定义的引用
menubox.c:(.text+0x396):对‘acs_map’未定义的引用
menubox.c:(.text+0x39e):对‘waddch’未定义的引用
menubox.c:(.text+0x3ad):对‘wmove’未定义的引用
menubox.c:(.text+0x3e3):对‘acs_map’未定义的引用
menubox.c:(.text+0x3eb):对‘waddch’未定义的引用
menubox.c:(.text+0x3fd):对‘waddnstr’未定义的引用
menubox.c:(.text+0x416):对‘acs_map’未定义的引用
menubox.c:(.text+0x41e):对‘waddch’未定义的引用
menubox.c:(.text+0x425):对‘acs_map’未定义的引用
menubox.c:(.text+0x42d):对‘waddch’未定义的引用
menubox.c:(.text+0x434):对‘acs_map’未定义的引用
menubox.c:(.text+0x43c):对‘waddch’未定义的引用
menubox.c:(.text+0x443):对‘acs_map’未定义的引用
menubox.c:(.text+0x44b):对‘waddch’未定义的引用
menubox.c:(.text+0x462):对‘wmove’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘dialog_menu’中:
menubox.c:(.text+0x4a4):对‘stdscr’未定义的引用
menubox.c:(.text+0x528):对‘stdscr’未定义的引用
menubox.c:(.text+0x58b):对‘newwin’未定义的引用
menubox.c:(.text+0x59b):对‘keypad’未定义的引用
menubox.c:(.text+0x5de):对‘wmove’未定义的引用
menubox.c:(.text+0x5ea):对‘acs_map’未定义的引用
menubox.c:(.text+0x5f2):对‘waddch’未定义的引用
menubox.c:(.text+0x603):对‘acs_map’未定义的引用
menubox.c:(.text+0x60f):对‘waddch’未定义的引用
menubox.c:(.text+0x636):对‘wbkgdset’未定义的引用
menubox.c:(.text+0x63d):对‘acs_map’未定义的引用
menubox.c:(.text+0x645):对‘waddch’未定义的引用
menubox.c:(.text+0x6a2):对‘subwin’未定义的引用
menubox.c:(.text+0x6b3):对‘keypad’未定义的引用
menubox.c:(.text+0x81f):对‘wnoutrefresh’未定义的引用
menubox.c:(.text+0x86c):对‘wmove’未定义的引用
menubox.c:(.text+0x874):对‘wrefresh’未定义的引用
menubox.c:(.text+0x890):对‘wgetch’未定义的引用
menubox.c:(.text+0x99a):对‘delwin’未定义的引用
menubox.c:(.text+0x9a2):对‘delwin’未定义的引用
menubox.c:(.text+0xac2):对‘wnoutrefresh’未定义的引用
menubox.c:(.text+0xacb):对‘wrefresh’未定义的引用
menubox.c:(.text+0xb18):对‘delwin’未定义的引用
menubox.c:(.text+0xb20):对‘delwin’未定义的引用
menubox.c:(.text+0xb27):对‘stdscr’未定义的引用
menubox.c:(.text+0xc25):对‘delwin’未定义的引用
menubox.c:(.text+0xc2d):对‘delwin’未定义的引用
menubox.c:(.text+0xcdf):对‘wrefresh’未定义的引用
menubox.c:(.text+0xdf8):对‘stdscr’未定义的引用
menubox.c:(.text+0xfb9):对‘wbkgdset’未定义的引用
menubox.c:(.text+0xfc0):对‘acs_map’未定义的引用
menubox.c:(.text+0xfc7):对‘waddch’未定义的引用
menubox.c:(.text+0x1059):对‘scrollok’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘do_scroll’中:
menubox.c:(.text+0x38):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘do_print_item’中:
menubox.c:(.text+0x17e):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘print_buttons’中:
menubox.c:(.text+0x2b8):对‘wrefresh’未定义的引用
scripts/kconfig/lxdialog/menubox.o:在函数‘print_arrows.constprop.0’中:
menubox.c:(.text+0x3c3):对‘wrefresh’未定义的引用
collect2: error: ld returned 1 exit status
scripts/Makefile.host:100: recipe for target 'scripts/kconfig/mconf' failed
make[1]: *** [scripts/kconfig/mconf] Error 1
Makefile:541: recipe for target 'menuconfig' failed
make: *** [menuconfig] Error 2


这是缺少了ncurse库.


执行sudo apt-get install libncursesw5-dev

正在读取软件包列表... 完成
正在分析软件包的依赖关系树      
正在读取状态信息... 完成      
将会同时安装下列软件:
  libtinfo-dev
建议安装:
  ncurses-doc
下列【新】软件包将被安装:
  libncursesw5-dev libtinfo-dev
升级了 0 个软件包,新安装了 2 个软件包,要卸载 0 个软件包,有 319 个软件包未被升级。
需要下载 275 kB 的归档。
解压缩后会消耗 1,582 kB 的额外空间。
您希望继续执行吗? [Y/n] y
获取:1 http://archive.ubuntu.com/ubuntu xenial/main amd64 libtinfo-dev amd64 6.0+20160213-1ubuntu1 [77.4 kB]
获取:2 http://archive.ubuntu.com/ubuntu xenial/main amd64 libncursesw5-dev amd64 6.0+20160213-1ubuntu1 [198 kB]
已下载 275 kB,耗时 10秒 (26.2 kB/s)                                                                                                                                                  
正在选中未选择的软件包 libtinfo-dev:amd64。
(正在读取数据库 ... 系统当前共安装有 211311 个文件和目录。)
正准备解包 .../libtinfo-dev_6.0+20160213-1ubuntu1_amd64.deb  ...
正在解包 libtinfo-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在选中未选择的软件包 libncursesw5-dev:amd64。
正准备解包 .../libncursesw5-dev_6.0+20160213-1ubuntu1_amd64.deb  ...
正在解包 libncursesw5-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在处理用于 man-db (2.7.5-1) 的触发器 ...
正在设置 libtinfo-dev:amd64 (6.0+20160213-1ubuntu1) ...
正在设置 libncursesw5-dev:amd64 (6.0+20160213-1ubuntu1) ...
W: 目标 Packages (main/binary-amd64/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (main/binary-i386/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (main/binary-all/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (main/i18n/Translation-zh_CN) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (main/i18n/Translation-zh) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (main/i18n/Translation-en) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 DEP-11 (main/dep11/Components-amd64.yml) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 DEP-11-icons (main/dep11/icons-64x64.tar) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (restricted/binary-amd64/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (restricted/binary-i386/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (restricted/binary-all/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (restricted/i18n/Translation-zh_CN) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (restricted/i18n/Translation-zh) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Translations (restricted/i18n/Translation-en) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 DEP-11 (restricted/dep11/Components-amd64.yml) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 DEP-11-icons (restricted/dep11/icons-64x64.tar) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:63 中被配置了多次
W: 目标 Packages (universe/binary-amd64/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Packages (universe/binary-i386/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Packages (universe/binary-all/Packages) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Translations (universe/i18n/Translation-zh_CN) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Translations (universe/i18n/Translation-zh) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Translations (universe/i18n/Translation-en) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 DEP-11 (universe/dep11/Components-amd64.yml) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 DEP-11-icons (universe/dep11/icons-64x64.tar) 在 /etc/apt/sources.list:15 和 /etc/apt/sources.list:65 中被配置了多次
W: 目标 Packages (main/binary-amd64/Packages) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 Packages (main/binary-i386/Packages) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 Packages (main/binary-all/Packages) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 Translations (main/i18n/Translation-zh_CN) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 Translations (main/i18n/Translation-zh) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 Translations (main/i18n/Translation-en) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 DEP-11 (main/dep11/Components-amd64.yml) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次
W: 目标 DEP-11-icons (main/dep11/icons-64x64.tar) 在 /etc/apt/sources.list.d/sogoupinyin.list:1 和 /etc/apt/sources.list.d/ubuntukylin.list:1 中被配置了多次


然后 在执行make XXXXX_defconfig  (此处是否必要,不太确定)

再执行make menuconfig 就可以显示了.(终端的窗口不能太小,否则还是显示不了)


作者:liwei405499 发表于2016/12/13 11:50:40 原文链接
阅读:21 评论:0 查看评论

Java Swing

$
0
0

这里写图片描述

package com.hz.test;

import java.awt.Container;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class TestListener extends JFrame {

    private final int width = Toolkit.getDefaultToolkit().getScreenSize().width;
    private final int height = Toolkit.getDefaultToolkit().getScreenSize().height;
    //设置窗口的宽和高
    private final int windowWidth = 430;
    private final int windowHeight = 330;

    JLabel label;
    StringBuilder builder = new StringBuilder();
    public TestListener() throws HeadlessException {

        this.setTitle("登录");
        // 设置窗体位置和大小
        this.setBounds((width - windowWidth) / 2,
                (height - windowHeight) / 2, windowWidth, windowHeight);
        Container container = getContentPane();
        container.setLayout(null);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//      this.setResizable(false);//设置窗体不可改变大小
        this.setVisible(true);
        label = new JLabel("龙");
        label.setSize(100, 50);
        this.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                super.mouseMoved(e);
                int x = e.getX();
                int y = e.getY();
                label.setLocation(x, y);
                label.setText("x = " + x + " ,Y = " + y);
            }
        });
        this.add(label);
    }


    public static void main(String[] args) {
        new TestListener();
    }
}

这里写图片描述

package com.hz.test;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

public class JPopMenu_Demo extends JFrame {  

    // 弹出菜单的实现,弹出菜单是一个可弹出并显示一系列选项的小窗口  
    JPopupMenu popupMenu;   

    public JPopMenu_Demo() {  
        super("右键弹出式菜单"); // 调用父类构造函数  
        // 实例化弹出菜单   
        popupMenu = new JPopupMenu();   
        // 增加菜单项到菜单上  
        popupMenu.add(new JMenuItem("菜单项"));  
        popupMenu.add(new JButton("按钮"));   
        popupMenu.add(new JLabel("标签"));  

        myEvents();  

        setSize(350, 300); // 设置窗口大小  
        setLocation(400, 200);  
        setVisible(true); // 设置窗口为可视  
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时退出程序  
    }  

    private void myEvents() {  
        // 窗口的鼠标事件处理  
        addMouseListener(new MouseAdapter() {   
            // 点击鼠标  
            public void mousePressed(MouseEvent event) {   
                // 调用triggerEvent方法处理事件  
                triggerEvent(event);   
            }  
            // 释放鼠标  
            public void mouseReleased(MouseEvent event) {   
                triggerEvent(event);  
            }  

            private void triggerEvent(MouseEvent event) { // 处理事件  
                // isPopupTrigger():返回此鼠标事件是否为该平台的弹出菜单触发事件。  
                if (event.isPopupTrigger())   
                    // 显示菜单  
                    popupMenu.show(event.getComponent(), event.getX(),  
                            event.getY());   
            }  
        });  
    }  


    public static void main(String args[]) {  
        new JPopMenu_Demo();  
    }  
}

这里写图片描述

package com.hz.test;

import java.awt.BorderLayout;
import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;

public class TestTable02 extends JFrame{

    private final int width = Toolkit.getDefaultToolkit().getScreenSize().width;
    private final int height = Toolkit.getDefaultToolkit().getScreenSize().height;
    //设置窗口的宽和高
    private final int windowWidth = 430;
    private final int windowHeight = 350;

    JTable table;
    JScrollPane scrollPane;

    Vector<Vector<String>> data;
    Vector<String> columnNames;

    JButton tianjia,shanchu;
    Box box = Box.createHorizontalBox(); 
    DefaultTableModel dm;   
    public TestTable02() throws HeadlessException {
        window();
        initData();

        dm = new DefaultTableModel(data, columnNames);
        table = new JTable(dm);
        scrollPane = new JScrollPane(table);
        this.add(scrollPane);
        tianjia = new JButton("添加");
        shanchu = new JButton("删除");
        box.add(Box.createHorizontalStrut(130));
        box.add(tianjia);
        box.add(Box.createHorizontalStrut(35));
        box.add(shanchu);
        this.add(box, BorderLayout.SOUTH);
        initTianjia();
    }

    private void initTianjia() {
        tianjia.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                Vector<String> dataRow = new Vector<>();
                dataRow.add(66+"");
                dataRow.add("李四");
                dataRow.add("女");
                dataRow.add(20+"");
                dataRow.add("计算机");
                dataRow.add("");
                data.add(dataRow);
                dm.fireTableStructureChanged();
            }
        });
        shanchu.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int num = dm.getRowCount();
                if(num > 0){
                    dm.removeRow(0);
                    dm.fireTableStructureChanged();
                }

            }
        });
        table.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int index = table.getSelectedRow();
                dm.removeRow(index);
                dm.fireTableStructureChanged();
            }
        });
    }

    private void initData() {
        columnNames = new Vector<String>();
        columnNames.add("学号");
        columnNames.add("姓名");
        columnNames.add("性别");
        columnNames.add("年龄");
        columnNames.add("专业");
        columnNames.add("备注");


        data = new Vector<Vector<String>>();
        for (int i = 0; i < 20; i++) {
            Vector<String> dataRow = new Vector<>();
            dataRow.add(1 + i + "");
            dataRow.add("张三" + i);
            dataRow.add("男");
            dataRow.add(20 + i + "");
            dataRow.add("计算机");
            dataRow.add("");
            data.add(dataRow);
        } 
    }
    private void window() {
        this.setTitle("表格");
        // 设置窗体位置和大小
        this.setBounds((width - windowWidth) / 2,
                (height - windowHeight) / 2, windowWidth, windowHeight);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);//设置窗体不可改变大小
        this.setVisible(true);

    }
    public static void main(String[] args) {
        new TestTable02();
    }
}

这里写图片描述

package com.hz.test;

import java.awt.HeadlessException;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

public class JTreeDemo extends JFrame {

    private final int width = Toolkit.getDefaultToolkit().getScreenSize().width;
    private final int height = Toolkit.getDefaultToolkit().getScreenSize().height;
    //设置窗口的宽和高
    private final int windowWidth = 278;
    private final int windowHeight = 600;
    JTree tree;
    public JTreeDemo() throws HeadlessException {
        window();
        DefaultMutableTreeNode node = new DefaultMutableTreeNode("QQ");
        //子目录
        DefaultMutableTreeNode node_1 = new DefaultMutableTreeNode("好友");
        DefaultMutableTreeNode node_2 = new DefaultMutableTreeNode("亲属");
        DefaultMutableTreeNode node_3 = new DefaultMutableTreeNode("同学");
        node.add(node_1);
        node.add(node_2);
        node.add(node_3);
        //创建好友
        Fridents f1 = new Fridents("张三", 20, 1);
        Fridents f2 = new Fridents("李四", 20, 1);
        Fridents f3 = new Fridents("王五", 20, 1);
        DefaultMutableTreeNode node_1_1 = new DefaultMutableTreeNode(f1);
        DefaultMutableTreeNode node_1_2 = new DefaultMutableTreeNode(f2);
        DefaultMutableTreeNode node_1_3 = new DefaultMutableTreeNode(f3);
        node_1.add(node_1_1);
        node_1.add(node_1_2);
        node_1.add(node_1_3);
        tree = new JTree(node);
        this.add(tree);



        initWindow();
    }
    private void initWindow() {

        /**
         * 选中监听
         */
//      tree.addTreeSelectionListener(new TreeSelectionListener() {
//          
//          @Override
//          public void valueChanged(TreeSelectionEvent e) {
//
//              //获取最后一个选中的Component
//              DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
//              Object obj = treeNode.getUserObject();
//              //判断是否是叶子节点
//              if(treeNode.isLeaf() && obj instanceof Fridents){
//                  Fridents fridents = (Fridents) treeNode.getUserObject();
//                  System.out.println(
//                          fridents.getName() + " " + 
//                                  fridents.getAge() + " " + 
//                                          fridents.getId());
//              }
//              
//          }
//      });

        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                TreePath path = tree.getPathForLocation(e.getX(), e.getY());
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
                Object object = node.getUserObject();
                if(e.getClickCount() == 2 && node.isLeaf() && object instanceof Fridents){
                    Fridents fridents = (Fridents) object;
                    System.out.println(
                            fridents.getName() + " " + 
                                    fridents.getAge() + " " + 
                                            fridents.getId());
                }
            }
        });
    }
    public static void main(String[] args) {
        new JTreeDemo();
    }
    private void window() {
        this.setTitle("树状列表");
        // 设置窗体位置和大小
        this.setBounds((int) ((width - windowWidth)*1.0 / 1.1),
                 ((height - windowHeight) / 9), windowWidth, windowHeight);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setUndecorated(true);//去掉窗口的装饰
        this.getRootPane().setWindowDecorationStyle(JRootPane.WIDTH);
        this.setResizable(false);//设置窗体不可改变大小
        this.setVisible(true);

    }
}
作者:qq_33624284 发表于2016/12/13 11:51:46 原文链接
阅读:20 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>