java开发java一年工作经验工资了

本帖子已过去太久远了,不再提供回复功能。从事JAVA开发一年多了可不知道如何最优我的职业规划?
我从事JAVA开发一年多了,很想尽早的做到能独挡一面,达到项目经理水平!可不知道如何最优我的职业规划?&(北京网友)&
作为职场中的常青树—软件工程师仍将是目前和未来招聘市场的热点。随着软件行业的快速发展,软件工程师将出现不同的职业发展路径。下面我列举了几个常用的职业发展路径供你参考。
方向一、技术专家方向,随着技术应用在各行各业的日益深入,业务对特定领域技术的要求也越来越高,比如搜索引擎技术、嵌入式开发技术、游戏开发技术,这就要求软件工程师不仅仅要掌握一般的软件开发能力,更重要的是需要掌握特定领域的技术知识和研发经验,后者的精通程度会让你在一般的开发者队伍中脱颖而出。
方向二、项目经理方向,随着软件外包行业的兴起,软件开发过程越来越专业化,对软件项目管理专业化程度的要求会越来越高。这样就需要一大批专业的项目经理来管理软件开发项目,项目经理不仅仅要有软件开发经验还要掌握项目管理方法、行业知识。
方向三、产品经理方向,产品经理在软件公司尤其是互联网公司在产品线越来越多的情况下,需要有专业的人负责整个产品生命周期的管理,在此基础上出现了产品经理的职位,在绝大多数互联网公司以及一些规模比较大的公司都有产品经理的职位,软件行业的产品经理需要有一定的技术背景,能够跟研发人员很好的沟通;同时也要有业务背景,需要能够配合市场和销售人员推广所负责的产品,需要综合能力非常强的复合型人才。
由于你提供给我关于你个人的信息并不多,我很难给你一个最优的职业规划。不过我可以给你一些大致的建议。
建议1、首先了解自己的真实期望,如果你希望成为专家型人才,你可以往技术专家的方向努力;如果你希望成为管理型人才,可以往项目经理的方向努力;如果你希望成为复合型人才,可以往产品经理的方向努力。
建议2、了解自己的职业优势,也就是说你天生或者后天的工作积累对你能否在职业上有良好的发展会很有帮助。这个包括两个方面,先天的部分可以包括您的职业性向、职场风格、职业价值观等,这些对你能否在职场上得到好的发挥很有帮助;后天的部分可以包括您的学历背景、工作经验都可以作为你在职业规划时的参考。
建议3、了解岗位对能力的真实需求,每个岗位对员工能力有一定的需求,比技术专家方向对于问题解决的能力就比较强,需要员工掌握很好的解决问题的方法;项目经理和产品经理对沟通的能力比较强,需要能够跟内部客户和外部客户的沟通。
以上回答,希望能对你的职业规划有帮助。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。工作一年的java程序员该达到什么样的水平呢 - ITeye问答
本人主要做web方面的开发,具体指各项技术的掌握程度,希望大家指点一下.
采纳的答案
如果非得说1年后的水平,那什么样的人都有,有些人跟刚毕业的水平差不了多少,只是编码熟练程度提高了。有些人却超越了大部分3、4年经验的程序员的水平。
结果怎样要看你付出多少。你认为呢?
至于方向,我觉得对框架的掌握不是主要的,首先要弄明白框架为什么要用。但也没必要去研究框架的实现、源码——除非你兴趣。
如何弄明白框架的用处呢?比如说hibernate有什么用呢?这个问题其实是在问ORM的作用。Hibernate实战的第一章关于对象模型和关系模型不匹配讲得非常明白(但那本书的中文版我只建议你读第1章)。也许你这时候又会问,对象模型有什么好处?那你可以去看看早期JavaEye关于领域模型的讨论帖子,还有陶文同学前段时间在JavaEye发的两个领域模型的讨论帖,还有就是读读《领域驱动设计》这本书(中文译本也挺差的,我只是告诉你往这方向去关注)。然后你会开始弄明白到底什么是面向对象,面向对象究竟有什么好处,也不会再在“接口和抽象类的区别”、“接口的作用是什么”这类初级问题上耗费时间。也许你的方向会开始转向一些敏捷实践……
也许有时候你觉得一些概念很难看懂,没关系,多看多想多实践,积累多了慢慢就会领悟。
还有,注重代码质量是最基本的素质,可以去关注一下相关的主题比如重构。但在这之前,你要弄明白为什么提高代码质量是重要的事——当然相关书籍在开篇一般都会提到这个问题。
其实我觉得最重要的是:你本身主观上是否有强烈的提高自己的愿望。如果没有,以上这一切都白说。
一年,以我的标准的话:
1、java基础,除开多线程、IO流、特殊算法等
2、ssh框架一定要熟练掌握其开发流程(不一定是ssh,其他框架也要触类旁通)
3、映射方面一定要熟练
4、前端方面一定要回常用的,类似于jquery+ajax返回个json类似的
5、数据库方面写个函数啊,存储过程之类的
6、对于项目、业务流程要整体有个理解,至少你要知道每个模块做什么的
我觉得一两年的就是一个熟练度的问题,编码,业务等各方面的熟练度都要提升就对了。
很难说,但是不能以时间来评估自己。而是用行动来评估自己。
一年和十年是一样的,如果自己没有实际行动的话。
楼上说得都很精彩,受益良多,我也认为专注是很重要的。
会做人的人1年的水平就能爬上去
不会做人的人4年的水平依然还是个coder
很简单,在开始的一年里要对java的知识结构有一个整体的认识,知道哪个知识点是做什么用的,处于整个知识结构的哪个位置,了解了这些,你应该算是入门了.
接下来你就可以针对你项目中使用到的技术深入学习,一个一个的掌握.
这个东西很主观,看你这个杯子里能装愿意装多少东西了,得到和失去是平衡的。
某人说,把冰箱里放满披萨,想要什么样的编程深度都可以~~
所以专注
因人而异,你不学习,5年经验可能还比不过应届的
一年可以说还是初级水平吧,
做web开发要懂的东西很多,
一年根本就太短了,
我认为java两年才入门,5年一个坎。
这样子,你去找一家公司面试,工资是你现在的两倍。
如果面试成功了,证明你达到了1年java的水平,
如果不得行,那再练练.
我面试一个工作三年的,面的是WEB岗位,他以前是做DELPHI的,你能说他水平不行?我认为关键是做一行,然后把这行里面的问题搞精搞透
首先基础技术要计较扎实了。面对没见过的问题能短时间内解决。对要实现的功能有自己的想法。
其次就是在这一年中你通过自己的努力学会了多少东西。不是在工作中的项目,那个不同人机遇是不同的。而是你在休息时间学到的东西!
长期潜水的小菜出来冒个泡~~
Web 开发实际是以浏览器为"虚拟机"的二次开发,当然要想办法了解这个"虚拟机"是最重要的.....
最低标准:熟练干活.
最高标准:业务熟练、工作中常有"新想法",除了工作用到技术以外能熟练使用一门技术.能带小弟.
我认为1年工作经验,应该可以达到以下的程度:
1.有扎实的java基础。
2.对常用的j2ee框架的机理有所了解,能单独熟练使用,可以对框架进行简单的修改。
3.对数据库的链接和掌握基本的几种DB的使用。
4.对新技术时刻关注,吸收新技术的优点来完善老的技术上的缺陷。
5.有较好的英语阅读能力(日语还可以,有些日语资料也很有价值),至少可以能看懂大致的英文文档。
6.对工作充满激情。
一年工作经验能达到这些应该就差不多了吧,望大家指正。
数据库设计
java基础知识也是很重要滴~
javascript,jsp,servlet等。
引用
我觉得,基础是最重要的,
1、面向对象的思想一定要掌握的很清楚,最好能用uml工具;
2、java基础知识,如java线程、集合类的使用等,需要达到不用工具,手写代码的程度;
3、对一些常用的框架,如struts、hibernate,应掌握其使用配置方法;
4、分析使用数据库;
5、j2ee,应掌握http、servlet的原理以及使用;
gangwu (初级程序员)
基础是基础了点,不过工作一年的人不仅仅只是了解这些吧?我感觉起码对hibernate以及spring的内核以及整个架构都得有一个了解。而且至于java的基础只是,我感觉不仅仅停留在基础,要灵活..学了一年丢人应该能够在实际开发中,针对业务,选择最好的实现。以及对设计模式的掌握。
我觉得,基础是最重要的,
1、面向对象的思想一定要掌握的很清楚,最好能用uml工具;
2、java基础知识,如java线程、集合类的使用等,需要达到不用工具,手写代码的程度;
3、对一些常用的框架,如struts、hibernate,应掌握其使用配置方法;
4、分析使用数据库;
5、j2ee,应掌握http、servlet的原理以及使用;
4what 写道
我觉得楼主不如思考另外一个问题:1年来,我每天花多少时间在自身的提高上?
不问结果。
这才是根本。
很多人的提高是被动的,但好处也是大大滴,嘿嘿,另:楼主这个问题太难回答了。
一年的时间里,学的是经验,自学的是知识。书还要不断地看。新技术要不断地去学。现地更新太快了。
觉得我说得好的,我要的不多,5秒钟的掌声,还有lz的分数。
我觉得楼主不如思考另外一个问题:1年来,我每天花多少时间在自身的提高上?
不问结果。
这才是根本。
竟然是搞web开发的,一年后,应该能对几个主流的框架比较熟悉。对一些异常能马上就知道在那里发生及解决。然后再对数据库有更加深的了解。对OO,设计等到应该要一定的认识。
其实最主要的是,应该要学会独立思考了。即结合,一年的经验,开始思考或总结吧。
我觉得做web开发需要学的东西还是很多的,最好的是能专精一样技术,例如j2ee或者.net 然后知识要广博,搞j2ee不能就只知道java那点东西,除了什么框架外,重要的是行业的应用,例如工作流,CRM等等。其次linux 数据库(orcale、sqlserver、mysql)都要熟悉。其实web开发里面还有好多方向,搞精一个应该也不错了,可能最重要的还是要专注吧,呵呵。
这个问题很模糊,一年,关键是看你在这一年中做了些什么事,学到了什么!不是每个人都能达到别人一年能达到的水平,这不像黄金分割点那样有准确值。如果你加油,每天总结,相信你一年后能力绝对比一年强;如果你是在混时间,那可想而知了,我现在在一家教育行业做开发,结果刚进去就在搞CMMI3的认证,说实话,好郁闷,有那么点软件工程思想,可对于CMMI3来说,我真的不想碰那东西,哪个中小型公司真能按那步骤一步一步实施?想走,可现在金融危机。所以你不要纯粹的想一年后你是什么样的水平,每天总结,你每天就在进步。呵呵,祝你早日成功,相信你一年后会比你预期的要强很多。
已解决问题
未解决问题7158人阅读
摘要&大学就开始学习web,磕磕绊绊一路走过来,当中得到过开源社区很多的帮助,总结了这些年来的技术积累,回馈给开源社区。
ps:图片都是从网上盗。。。感谢原作者。 ps:文字千真万确都是我自己写的。 在此,特别感谢Hansen,他曾经有私的帮助过我(两包零食),他是一个很强的启蒙胖子。
我把我这些年在java学习中学到的东西,按照项目开发中可能遇见的场景,进行了一次梳理。&
& &&这个故事是我最后决定加上来的,我非常喜欢这个故事,软件工程中有一个被戏称为Cargo
Cult编程法的编程风格,而下面这个故事讲述了此编程法的来源:&
& &&早在40年代,据说,美军曾驻扎在一个偏远的岛屿。岛上的土著居民在此以前从未见过的现代文明,所以,他们对联军和他们带来的东西非常惊奇。他们发现联军修建了机场跑道和控制塔,带着耳机的士兵对天呼叫,然后满载着大量货物的大铁鸟便从天而降。当铁鸟降落后,货物便分发给所有岛上的人们,为人们带来繁荣。&
& &&终于,有一天,部队离开了,大铁鸟也不再回来了。为了再次得到货物,岛上的土著居民用竹子建造了自己的跑道,控制塔,让他们的头领登上平台,并让他戴上用椰子做的耳机。但无论他们如何努力尝试,大铁鸟再也没有回来。&
& &&几十年后,研究人员发现了该岛。岛上的土著居民仍旧保留着这一宗教仪式。他们把岛上居民的这一奇怪的宗教仪式命名为“Cargo
@考虑这样一个应用场景:我们的项目功能日渐强大,代码却日渐臃肿,我们如何将代码变得有条理些?&
& &&无论我们是学习还是工作,我们的前辈总是会告诉我们,我们需要把java项目进行架构上的分层,界面层(UI)&&业务逻辑层(BLL)
数据访问层(DAL),就像Cargo Cult中的土著居民一样,虽然我们并不知道为什么高手们要那样做,但是我们相信这么做可以让程序工作起来,后面我会讲到为什么会有所谓的经典的三层架构,现在我们已经做完的事是,按照三层架构将项目搭建并运行起来了!&
& &&我们一般会想到MVC,很多书上都有写到,可惜很多时候我们理解的MVC是错误的。。。甚至我曾经天真的以为,MVC正好对应着DAL,UI,BLL。。。实际上,这两者并没有显式的关系,前者属于设计模式,而后者属于架构设计的范畴,如果一定要扯到一起的话,关系可能会是这样的:&
& &&实际上,Controller是很薄的一层,它仅仅负责接收参数,封装参数,调用不同的service。所以我们可以考虑先从它入手,简化代码。&
& &&我们现有的controller做法是,不同的业务调用不同的servlet,通过参数的不同,调用不同的方法,比如,有下面一个form&
&form&action=”UserServlet?command=login”&&
&&&&&input&name=”name”&/&&
&&&&&input&name=”password”&/&&
& &&如果我们在这个表单中输入用户名密码,最终后台会将这个请求提交到UserServlet中,然后根据command=login,调用UserServlet中的login方法。在login方法中,会有这样的一段代码:&
String&name&=&request.getAttribute(“name”);&
String&password&=&request.getAttribute(“password”);&
Boolean&result&=&userService.hasUser(name,&password);&
if(result)&{&
&&& &&我们可以发现,基本上这个servlet中,所有的方法几乎都有着从request中获取参数的这么一个过程,而且同一个servlet中,需要获取的参数大部分都是重叠的(比如UserServlet中,几乎所有的方法都需要获取name和password的值,才能进行近一步操作),既然每一个方法都有这么一个需求,为什么不考虑将这一过程抽象出来呢?&
& &&首先,我们可以设计一个叫AaronDispatcher的类,它负责截取了所有的对项目的访问的http请求。&
& &&比如,我们上面的请求叫UserServlet?command=login,同时传递三个参数name和password(以及上面的command)
。AaronDispatcher巨牛叉,它直接把这个请求截取了,并进行分析,首先它的名字叫UserServlet,调用的方法叫login。为了不引发歧义,我们更改前台的请求地址,改为发送到UserAction?command=login。&
& &&然后我们可以重新设计UserServlet,创建全新的UserAction。(现已加入豪华午餐)&
public&UserAction&{&
&&&&String&&
&&&&String&&
&&&&String&&
&&&&String&&
&&&&......&
&&&&public&login()&{&
&&&&&&&&...&
&&&&public&logout()&{&
&&&&&&&&...&
&&&&public&updatePassword()&{&
&&&&&&&&...&
&&&&......&
& &&(眼疾手快的人也许可以注意到一点:这个类不再需要接受HttpServletRequest及HttpServletResponse作为参数了)&
& &&每当我们有一个发送到UserAction的请求,AaronDispatcher就帮我们new一个新的UserAction实例,同时将请求中的参数赋给UserServlet中的属性。具体的底层做法,类似于下面这样:(实际上会复杂很多,不会直接new对象,而是使用反射来创建对象并赋值属性)&
UserAction&userAction&=&new&UserAction();&
userAction.setName(request.getAttrbute(“name”));&
userAction.setPassword(request.getAttrbute(“password”));&
userAction.setNewpassword(request.getAttrbute(“newpassword”));&
userAction.setOldpassword(request.getAttrbute(“oldpassword”));&
& &&如果我们需要登陆功能,直接调用userAction.login()就可以了(至于name和password,直接可以在方法内部获取当前对象属性)。&所有的方法中,从request中获取参数并进行封装的这么一个过程,全部都被巨牛叉的AaronDispatcher做了,是不是减少了很多重复的代码量?!&
& &&可能会有疑虑,所有的请求,无论什么方法,都进行一次属性全赋值,如果前台没有传入这个属性,不就为空了嘛?但是要知道,如果我们调用login这个功能,newpassword和oldpassword固然会因为前台没有相应的属性值传入而设为null,但是,但是,在login方法中,我们根本就不会用到这两个参数啊!所以即使为空也不会有错的!&
& &&甚至我们可以做的再牛叉一点,AaronDispatcher会去读取一段配置文件,配置文件中指定了什么样的请求调用什么养的类以及相应的方法,这样我们就可以彻底解耦最前方的Controller了!&
& &&但是AaronDispatcher是怎么做到无论什么类,当中有什么属性,我们都不需要事先知道,我们都可以接收前端参数,给他们的属性赋值呢?(答案是通过反射)&
& & 现在,我们已经成功的重新发明轮子了!&
& &&因为以上这个伟大的想法已经有被别人抢在前面实现了,就是著名的Struts2,毋庸置疑,Struts2的核心功能就是这么简单。&
& &&在Struts2中,每一个处理类被称之为Action,而Struts2也正是通过xml配置文件,实现了无需要修改代码,通过修改配置文件,就可以修改Controller。&
& &&Struts2发展到今天已然是一个功能齐全的庞然大物了。&
& &&正如一开始所说,MVC框架只不过帮助我们封装了请求参数,分发了请求而已。Controller是非常薄的一层,而我们的业务逻辑都是由BLL层提供的Service对象实现。
& &&首先讲述一下为什么会有所谓BLL(Business Logic Layer)和DAL(Dataaccess
Layer)了。在一个项目中,无论是查询用户的用户名,还是查询库存数量,这些数据终归是要保存到数据库的,而这些对数据库的操作将会无比的频繁,如果我们不将这些对数据库表的操作独立出来,如果在多个方法中存在着对一个用户记录的查询,我们不得不把这段代码copy、paste无数次,既然这样,我们为什么不像上面那样,将这种可能会多次遇到操作抽象出来呢?于是就有了所谓的DAL了,这样,无论在什么地方,需要用到数据库查询相关的工作的时候,仅仅需要这么做:&
User&user&=&userDaoImp.getUserById(userId);&
& &&这么做有一个好处:减少了因为持久化方案的更换而导致的代码修改带来的工作。&
& &&持久化是一个非常高端大气的专业术语,说的更专业一点,就是将内存中的数据保存到硬盘中。在我们的项目中,用户进行了注册,我们需要将用户注册的用户名密码保存起来,以便下次用户登陆的时候我们能够知道,这个用户名的用户是合法注册过的。
& &&通常持久化的方案就是将数据保存到数据库中,但是我相信如果我不愿意使用数据库,而直接将用户名密码明文保存到文本文件中,也没有人会从技术上反对吧(实际上这种事情在中国互联网的发展历史中还真发生过。。。),如果我真的选择这么做,我所需要做的工作就是仅仅修改DAL中的实现,将对数据库的操作改为对本地文件的操作,而无须修改调用持久化方法的方法。&
& &&业务层负责业务的处理(接收上层传过来的信息进行处理),当处理完之后,将处理的结果利用DAL的对象进行“保存到硬盘”。而DAL具体是怎么实现的,完全不会影响到已实现的业务。&
& &&很明显的,为了做到上面这一点,DAL中的方法要尽量的“单纯”,不包含任何的业务上的逻辑,仅仅是将内存中的数据(一般就是某个对象)保存到硬盘的“实现”,以及从硬盘读取的数据提取到内存的“实现”。&
& &&已经很明显了,三层架构不是从来都有的,只不过是在无数次痛苦的经历过后先烈们总结出来的一套证明可以在某一方面减少因变动而带来的额外工作量。说它经典,也只不过是因为它实现了展示、业务、持久化这三个必不可少却又相对对立的需求的切割(不过确实有的项目中,展示不是必选的)。&
& &&所以基本上所有的复杂架构也只不过是在此基础上的进一步分割,曾经做过一个巨复杂SaaS项目,为了减少某些不定因素的变动而带来的代码上的改动,架构师将BLL分成了两层,在原有的BLL之上又增加了一层core
business layer。这样MVC框架只需要调用core business的业务而无须自己在重复组装比较底层的业务逻辑了。&
& &&如果有更复杂些的项目的话,就需要通过分割子项目及更复杂的层级关系来解决了。&
& &&这个时候我们或许应该讲述BLL了,不过在此之前,我们可以再多想一步,能不能修改DAL中的东西,让我们使用起来更简单?&
& &&一般来说,数据库中的表对应着java中的类,表中的一行记录对应着一个entity对象,表中的字段对应着对象中的属性,我以前一直觉得很神奇,这就是传说中的ORM。这当中还有很多更复杂的东西,比如多表级联的结果映射为对象,在这里我们先忽略这些复杂的情况。&
& &&有了上面的知识,我们可以发现, 如果我们选择关系型数据库作为持久化方案,我们的DAL其实也很“单纯”,他们所做的也不过是将对象属性通过sql存储到数据库、将通过sql获取的数据封装为对象。&
& &&同样的我们可以写一个巨牛叉框架(好吧,这次不是写一个巨牛叉的类了),它会自动根据我们entity的名字,去数据库寻找相应的表,当我们调用insert,delete,update,select等方法的时候,它会自动帮助我们根据要求及参数拼接sql,然后去数据库查询/修改记录,如果是查询,则把查询出来的记录集封装成对象,保存在list中。这样,我们就可以在DAL中简单的定义一些entity就可以了。&
& &&比如,我们这次在DAL中,仅仅只定义了一个类:&
public&User&{&
&&&&long&&
&&&&String&&
&&&&String&&
& &&是的,剩下的事全部交给这个巨牛叉的框架来做了,当我们需要在UserService中查询一个用户记录的时候,我们只需要这么做:&
AaronDao&userDao&=&new&AaronDao(User.class);&
List&User&&list&=&userDao.list(......)&
&&哇~,生活瞬间变得很美好,这个巨牛叉的框架太棒了,只要定义好entity就可以完成以前需要成千上百行才能完成的功能,我连数据库的刷库脚本都不用写了~这么巨牛叉的框架一定会帮我们做好这些的。我恨不得马上就使用这个框架来开发我下的一个项目。&
& & 只可惜java中还真没有这种框架。。。&
& &&实际上java的JDBC远比想象中的复杂(主要是因为作为强异常处理的java语言,为了完成一次对数据库的操作,需要编写的异常处理代码实在太多了),还有事务的处理,数据库连接的开启和释放(甚至连接池的配置),等等等等。。。如果使用Spring
JDBC或者Hibernate ORM框架,可以帮助我们不需要花太多精力放在非核心的处理上,专注于数据的读/写。&
& &&即使这样,需要写的代码还是太多了。因为每一个entity我们都必须手动编写相应的Dao类(注:操作entity的类),我又开始怀念那个巨牛叉的框架了。如果大家有兴趣,倒是可以尝试一下实现我上面所形容的据牛叉的DAL框架。&
& &&实际上,真的有人在Ruby中实现了类似于上述的数据库操作框架,在Ruby
On Rails中,我们仅仅只需要定义一些普通的entity,而剩下的操作都是ror自动生成,当年DHH(ror的作者)在网上发出15分钟从零开始完成博客系统的视频,整个Web世界都被惊叹到了。&
& &&在正式讲到BLL之前,咱们先怀念一下最原始的servlet,是的,就是它刚刚出生的时候的事。&
& &&最早的时候,sun在提出servlet规范的时候,很多人是直接在servlet中完成接收参数,处理业务,从数据库或者本地文件中读取数据,最后打印出html返回。这个过程,大概会长成这个样子:&
response.getWriter().println(“&html&”);&
response.getWriter().println(“hello&”&+&user.name);&
response.getWriter().println(“&/html&”);
&&不用怀疑,JSP出现之前很多大神早期真的都这么做过。&
& &&显然的,后来对数据库的操作被剥离出来作为DAL了,那为什么还要剥离BLL呢?&
& &&如果我们不剥离service对象(BLL),如果我们需要增加用户,我们需要在UserServlet中这样写:&
public&void&doPost(HttpServletRequest&request,&&HttpServletResponse&response){&
&&&&Strring&cmd&=&request.getAttribute(“command”);&
&&&&if&(“addUser”.equals(request.getAttribute(cmd)))&{&
&&&&&&&&String&name&=&request.getAttribute(“name”);&
&&&&&&&&String&password&=&request.getAttribute(“password”);&
&&&&&&&&User&user&=&new&User(name,password);&
&&&&&&&&if&(userDaoImp.getUserByName(“name”)&!=&null){&
&&&&&&&&&&&&userDaoImp.addUser(user);&
&&&&&&&&&&&&......
&&&&&&&&}&else&{&
&&&&&&&&&&&&......
&&&&&&&&}&
&&&&}&else&if&(其他command)&{&
&&&&&&&&......&
&&这当中只有一个简单的逻辑:如果用户名已经存在,则返回到错误页面,告知用户添加新用户失败。如果用户名不存在,则返回到正确页面,告知用户添加新用户成功。&
& &&如果我们想测试我们所写的代码是否正确,会遇到一个前所未有的困难,需要模拟HttpServletRequest和HttpServletResponse对象以及一个UserServlet对象。我们很难脱离浏览器环境测试这个类。(实际上可以通过mock来模拟这个过程,这个后面会说到)&
& & 简单的办法就是写好前端页面,然后通过在页面上去添加一个用户,看看是不是真以上逻辑正确。&
& &&天呐。。。这才是一个简单的业务逻辑,我们就不得不等到有了前端页面之后才能去测试它,如果我们的逻辑更复杂点,等到前端都做完了才能发现有后台有bug,而且即使修改完了还需要回头通过浏览器再测试一遍,如果是通过页面不断地手动输入用户信息这种,估计一天也就测试几个case了。。。大部分时间都浪费在键盘上了。&
& &&要是能把测试的case记录下来,下次由电脑自动的重新模拟这个过程该多好(正所谓重复劳动力全部交给电脑吧!),不过自动化测试在后面,我们先跳过这个疯狂的想法。
& & 还是修改源代码吧。。。&
public&void&doPost(HttpServletRequest&request,&HttpServletResponse&response){&
&&&&String&cmd&=&request.getAttribute(“command”);&
&&&&if&(“addUser”.equals(cmd))&{&
&&&&&&&&String&name&=&request.getAttribute(“name”);&
&&&&&&&&String&password&=&request.getAttribute(“password”);&
&&&&&&&&User&user&=&new&User(name,password);&
&&&&&&&&userService.addUSer();&
&&正如一开始所说,通过将servlet作为很薄的一层controller,真正的业务逻辑抛给service做,所有对业务的测试全部都可以简单的变为对service的测试。&
& &&比如我们可以简单的这样测试:&
public&static&void&main(String[]&args)&{&
&&&&UserService&userService&=&new&UserService();&
&&&&User&user&=&new&User(name,password);&
&&&&System.out.println(userService.addUser(user));&
&&servlet中唯一要做的,就是根据service的返回结果,返回不同的UI展示。&
& &&这样保证了一种“契约”:servlet负责调用service并提供相应参数,根据service的返回结果,返回不同的UI展示。只要service没有错误,servlet肯定能正确的执行MVC中对View的跳转。&
& &&而对service中业务逻辑的测试,在前期就可以通过简单的单元测试做完,保证最后提供出去的service都是正确的。相比较于将业务逻辑写入servlet,等到后期通过页面的操作才能发现bug,开发效率可以说是骤增。&
& &&实际情况当然会比我所说的例子复杂的多。。。&
& &&首先,现在很少有项目会直接采用servlet的形式来做,那样子的话我们不得不在很多地方重新创造轮子(还记不记得我设计的很牛叉的AaronDispatcher。。。),一般会采用MVC框架来封装servlet。&
& &&同时,我们会遇到很多很多诸如安全性,权限控制,异常处理等等之类的,需要解决的问题。(最后我们会发现,我们的业务逻辑的代码量和这些非业务逻辑代码量相比,要少的多的多)&
& &&对有些人来说,如果仅仅是为了测试而多做一层service的确看起来没有那个必要,三层架构不一定总是正确,有很多缺点,典型的贫血模型,不够面向对象(关于这一点,网上的资料好多,可以尝试一下);开发过程漫长;做出来的效果鱼龙混杂;(同样适用三层架构,大牛们和我设计出来的效果简直就是美食和狗屎的区别)&
& &&现实生活中,没有这么复杂的php也活得好好的。&
& &&但是,但是,但是。。。如果我们只是想做一个网站,它只需要记录我们的博客,展示我们曾经拍过的照片,提供一个供大家谈谈人生谈谈理想论坛,那么我建议使用php,的确做网站最好的是php,用java纯属装逼。java之所以是java(或者换句话,.net之所以是.net),他们与php的差别在于,他们有完整的命名空间机制(java中的package,C#中的namespace),完善的开发标准体系,成熟的第三方框架,语法简单、规则性强。事实上,java/.net绝对不适合做快速成型的展示型网站。&
& &&吐槽结束,回到上面的问题,既然三层架构绝对不是权威,仅仅为了测试还不值得我们抽象出一层BLL,那为什么我们要像Cargo
Cult土著居民那样,跟随别人的脚步呢?&
& &&因为我们还不够强。。。&
& &&因为我们还不够强,不能想到更好的分层办法,所以我们不得不沿用传统的三层架构或者在此基础上的多层架构,如果我们足够强大,完全可以利用领域模型的思维来构建系统。&
& &&因为我们不够强大,很多功能我们需要利用BLL才能实现。&
& &&正如前面所说,java工程师的方向绝对不是做一个简单的网站,如果项目领导突然有一天神经大条,说我们需要做一个iphone客户端,因为领导用的是iphone,如果我们没有把BLL抽象出来,我们就不得不重新写一个和web处理相同业务逻辑的层级,用来和iphone客户端通信。如果业务复杂,天呐。。。&
& &&正是由于我们已经将不依赖于任何显示逻辑的BLL抽象出来,我们才能淡然的添加一层薄薄的iphone客户端通信层,当需要发生业务逻辑的时候,仅仅只需要调用BLL已实现的方法。&
& &&通常三层架构中的UI最终会返回html给浏览器解析,而iphone通信层一般会返回json数据给iphone客户端解析。&
& &&好吧,的确不是所有领导都有iphone的,但是,即使我们确定我们仅仅需要支持的就是浏览器,很不幸,很多时候我们也需要利用BLL。&
& &&通常BLL中的每一个方法都是一个事务。事务是一个很复杂的东西,在分布式系统中更是如此,但即使是一个简单的项目,我们也不得不为事务而伤神。&
& &&在我们的潜意识中,事务应该是数据库访问层做的事,但是很不幸,我们需要在业务逻辑处理中进行事务。&
& &&最烂大街的例子,BLL中有一个AccountServer类,提供一个transfer(Double
money, Account from, Account to)方法。在这个方法中,首先会进行一次update(from),再进行一次update(to)的数据库操作,但是如果update(from),汇款操作成功了,但是因为某些未知原因,update(to),收款操作失败了,估计所有人都接受不了这件事。&
& &&所以我们要保证transfer(Double money, Account
from, Account to)作为一个方法,要么里面的数据库操作都成功,要么都失败。&
& &&抽象出业务逻辑层的好处在于我们可以以一种更好的颗粒度来做事务。&
& &&说点题外话。。。&
& &&不得不说,如果不利用Spring AOP来配置事务,纯手工编写的话,给BLL中的方法做事务,的确是一个很有技术含量的活。&
& &&这当中的确用到了很多设计模式的奇技淫巧、ThrealLocal等较为高深的技术(好吧,的确在一年之前,我真的不知道ThreadLoacl是什么。。。),因为我们做事务的一个前提是,事务中所有的数据库操作,使用的是同一个connection。&
& &&关于更具体的,如何简化BLL中的事务配置,以及面向接口的编程习惯,spring的使用,将会留到下一个应用场景。&
& &&现在我们来做一次总结:&
& &&MVC之类的设计模式、三层架构的划分,归根结底的目的在于解耦,减少项目中牵一发而动全身的现象,同时减少重复代码的编写,增加代码的可读性、复用性。&
& &&所谓框架,就是帮助我们减少重复的、不必要的、非业务核心的代码的编写的工具而已。(不然我们用它图什么呢?)&
& &&事实上,如果我们真的看完所谓23种设计模式,实际上只是在强调三个原则:封装变化点、对接口进行编程、多使用组合而不是继承。(这里主要注意第一点)&
& &&好吧,进入下面的应用场景。&
@考虑这样一个应用场景:我们已经深刻的掌握了三层架构的要领(事实上并没有。。。),并且使用了业内最牛叉的Aaron MVC框架来处理请求,一切都变得很美好。突然有一天,领导来了。。。&
& &&领导有一天突然发现,我们的UserService中的listUsers写的不够好,没有另外一个小组编写的UserService中实现的listUsers方法好,因为另外一个小组在listUsers中加了一个小判断,在列举出来的用户中,领导永远排在第一个。&
& &&于是乎,领导二话不说,让我们直接把Action中有引用到UserService的全部换成他们的UserService。&
& &&因为我们的UserService是这样子导入的:&
import&com.unis.team1.UserS
&&而他们的UserServcice则需要这样子导入:&
import&com.unis.team2.UserS
&&于是,我们不得不全文搜索所有的地方,&将import
com.unis.team1.UserService&改为import
com.unis.team2.UserService&
& &&如果很不凑巧,大家的命名方法不一样,另外一个小组的名字叫做com.unis.team2.UserServ,我就不得不全文搜索将import
com.unis.team1.UserService&改为import
com.unis.team2.UserServ&,&同时,全文搜索将UserService改为UserServ。&
& &&这一切的一切的罪恶的根源,源于如下的代码:&
import&com.unis.team1.UserS&
public&UserAction{&
&&&&UserService&userService&=&new&UserService();&
&&&&.......&
&&是时候改动BLL了。&
& &&我们添加一个接口:&
public&interface&IUSerService&{&
&&&&List&User&&listUsers();&
&&同时,无论是我们编写的com.unis.team1.UserService还是别的小组编写的com.unis.team2.UserServ,都实现了此IUSerService接口。&
& &&于是,导致罪恶的代码被修改为这样:&
import&com.unis.service.UserS&
public&UserAction{&
&&&&IUserService&userS&
&&&&.......&
&&我们知道,java面向对象中多态的特性,可以这样子:&
Animal&cat&=&new&Cat();&
&&我相信,上面这个代码谁都知道,只可惜,不是所有人都能真正理解实现这个的意义。。。&
& &&回到刚才的罪恶的代码,我们在Action中定义了service的接口,可是那又怎么样呢?最终不还是需要new一个具体的实现吗?如果我们new了UserService,后面需要替换的时候,还是需要换成new
UserServ啊!&
& &&嗯,所以我们就要想办法不需要自己在代码中new!跟往常一样,我们设计一个超级牛叉的Aaron
Container框架,它能完美的和Aaron MVC结合。&
& &&我们定义了如上的UserAction,但是实际上我们真正使用的UserAction并不是我们自己new出来的,而是每次有一个请求到来的时候,由Aaron
MVC创建的,创建的过程可以这么去理解(实际上的情况要复杂的多,可以看出,Aaron MVC就是一个山寨版的struts2,action的创建远远比这个复杂!):&
UserAction&userAction&=&new&UserAction();&
IUserService&userService&=&new&UserService();&
userAction.setUserService(userService);
&&好了,这样子,虽然我们没有在定义UserAction的代码中指定接口的具体实现,但是框架技术已经帮助我们把需要用的实现类给“注入”进去了。这样子,我们可以任意的在配置文件里面配置在“运行时”,具体使用哪一个接口的实现类。(虽然有点绕,还是好好理解这句话)&
& &&如果仅仅是为了动态的替换实现类,就将所有本来一个类就能完成的事拆分成接口和实现类,好像也说不过去哦。。。不过,领导怎么会这么轻易地善罢甘休呢?&
& &&领导决定放大招了,他觉得既然我们现在已经分离出了BLL,那么他希望BLL中的每一个方法执行前,都进行一次log记录,记录的格式大概如下:&
& &&“谁谁谁”于“什么什么时间”进行了“什么什么操作”&
& &&我可以骂人吗?!在提干的假设中,我们的项目已经做的很庞大了,也就是说,我们的BLL中有上百个类,上千个方法!也就是说,为了领导的一句话,我们不得不Ctrl
C V上千次,而且还有可能有遗漏。。。&
& &&是时候让史上最牛叉的Aaron Container框架出场了!&
& &&上面已经说了,Aaron MVC会帮助我们自动生成Action,而当中如果有需要用的BLL中的接口,会被自动“注入”我们需要的实现类,我们修改一下这个过程:&
UserAction&userAction&=&new&UserAction();&
IUserService&userService&=&AaronContainer.get(IUserService.class)&
userAction.setUserService(userService);
&&也就是说,IUserService userService = new UserService()这个过程,被替换为AaronContainer.get(IUserService.class),意义何为呢?(我又想说了。。。这真的只是给大家理解的过程而已,思想上接受就行了,真正的过程绝对比我所描写的这三行代码多几百倍)&
& &&先介绍一下可爱的代理模式吧。。。&
public&interface&Test&{&
&&&&public&void&test();&
public&AaronTest&implements&Test&{&
&&&&public&void&test()&{&
&&&&&&&&System.out.println(“hello&world&!”);&
public&AaronTestProxy&implements&Test&{&
&&&&public&Test&testI&
&&&&public&AaronTestProxy(Test&test)&{&
&&&&&&&&this.testImpl&=&&
&&&&public&void&doBefore()&{&
&&&&&&&&System.out.println(“do&before&!”);&
&&&&public&void&doAfter()&{&
&&&&&&&&System.out.println(“do&after!”);&
&&&&public&void&test()&{&
&&&&&&&&this.doBefore();&
&&&&&&&&this.testImpl.test();&
&&&&&&&&this.doAfter();&
&&我们原本有一个Test的实现类AaronTest,如果我们要调用AaronTest的test()方法,原本我们需要这么做:&
Test&test&=&new&AaronTest();&
test.test();
&&结果显而易见,打印出:&
& & hello world !&
& &&但是如果我们使用代理类,我们可以这么做:&
Test&test&=&new&AaronTestProxy(new&AaronTest());&
test.test();
&&结果打印出这样:&
& & do before !&
& & hello world !&
& & do after !&
& &&相信聪明的孩子已经看出来了,通过代理类,我们可以在原本需要实现的方法实现之前/之后做点别的事。&
& &&而想要完成这一点,关键就在于——接口!&
& &&我们声明需要的只是某一个接口,我们提供的是代理之后的实现。&
& &&我们将核心的逻辑放入接口实现类,而公共的非业务逻辑放入代理实现类,通过代理实现类包装业务逻辑,我们就可以全心全意的将精力放入业务逻辑的实现,而将权限控制、日志记录、异常处理等功能,由代理类实现。(比如上面的doBefore方法,完全可以用来记录日志)&
& &&这也是设计模式第二个原则:面向接口编程。&
& &&现在假设我们的Aaron Container框架已经帮助我们代理了所有的service实现类(前提是,service都是接口!!!)于是乎,所有在需要service实现类的地方,我们都只是声明一个接口,Aaron
Container会自动将代理类注入进去!&
& &&而且,我们的Aaron Container框架已经聪敏的成精了,AaronContainer.get(IUserService.class)这个过程,返回的是包装了我们所编写的UserService的代理类,当我们执行当中的方法的时候,代理类首先先记录一下日志:&
& &&“谁谁谁”于“什么什么时间”调用了“什么什么方法”&
& &&然后再调用UserService中的我们所编写的带有业务逻辑的方法。&
& &&好了,现在我来总结一下这一套“复杂”的过程:&
& &&首先是我们将service分为接口和实现。&
& &&然后在需要service方法的地方声明了相应的接口。&
& &&OK,我们工作结束了。&
& &&然后,Aaron框架套件会帮助我们利用一些列高阶的java技巧,完成剩下的工作。&
& &&将需要用到service的地方“注入”具体的“实现”,而这当中,所有的“具体实现”,不再是简单的我们自己所编写的service实现,而是经过包装(也就是代理)后的代理实现类。&
& &&代理实现类很牛叉的帮助我们在运行具体业务逻辑方法之前/之后做点别的事,比如记录一下日志,检测一下用户权限是否匹配,事务的声明什么的。&
& &&理解上述的过程还是十分简单的,不过我仍然要说一下,具有人工智能的Aaron框架套件仍处于开发中,所以我们还不能因为我们的领导想添加日志,框架就会帮助我们实现代理类的日志记录,所以我们需要自行编写代理类的日志记录行为(这当中的步骤远比我形容的困难,我们甚至需要获取到当前用户的信息)。&
& &&现在我们来看一看Aaron Container到底做了些什么吧:帮助我们生成某个接口实现类的代理类,在我们所有的编写的需要这些实现类的地方,我们都不再需要人为的“new”了,我们仅仅需要声明我们需要这个接口,然后它会帮助我们将生成代理类“注入”到声明了有接口的地方。因为所有的代理类都是从Aaron
Container“拿”出来的,所以运行的时候调用这些代理类的某个方法的时候,很容易就可以做到添加点别的功能,而无须修改我们自己编写的那个实现类。&
& &&这就是所谓的依赖注入(或者高端大气一点叫做控制反转),我们无需自己new,仅仅只需要声明,真正需要用到这个对象的时候会被“注入”进来。&
& &&好吧,这就是Spring的核心,一个大大的container,负责创建“实现了某个接口的业务逻辑对象”的代理对象(这么说很狭隘,实际上要是愿意,我们可以将大部分对象都交由Spring管理)。&
& &&Spring帮助我们管理需要被管理的对象的生命周期,简单来说,就是我们可以通过配置文件,控制这些需要被管理的对象什么时候生成,生成的时候加点什么操作,什么时候销毁,销毁的时候加点什么操作(比如在销毁的时候记录一下日志“我死了。。。”)什么的,一切都变得可控了。&
& &&而且我们可以随时替换具体的实现类,因为我们在源代码中并没有硬编码声明我们需要new“哪一个”具体实现类!!&
& &&是的,这就是Spring的核心,听起来好简单,没什么大不了,但是的确就是这样。&
& &&而Spring AOP(这个会在很多地方看到的专业术语),也只不过是因为Spring帮助我们通过代理类管理了类的生成和注入从而才有的“附加功能”。AOP的含义简单来说,就像上面我们需要在每一个BLL中方法被调用时记录一下日志那样,因为所有的BLL中的具体实现类对象都由Spring来管理,当我们需要“横切”,对所有对象统一的加一个“调用方法时记录这个操作”这个操作时,只需要在一个地方声明一下我们需要在方法调用之前进行日志操作,就可以完成对所有BLL中的方法添加记录日志这个功能,这就是AOP。&
& &&再次记住这句话,依赖于接口,而不是依赖于具体的某一个类(通俗一点的说就是不要在代码里面直接new某个实现类对象),可以帮助我们减少很多代码量,同时提高项目的扩展性,扩展性在于,我们不需要修改已有代码(重中之重!!!),就可以替换行为,而在java中,如果不面向接口编程,这是无论如何都做不到的。&
& &&再次给我挚爱的Ruby做一次广告,为什么Ruby的开发速度比java快?为什么Ruby/Python不需要接口?&
& &&脚本语言在运行的时候可以动态的修改类里面的行为,而java需要先编译,一旦编译好的类,我们就无法再次去修改他们了,所以脚本语言不需要像java那样,事先定义好很多接口才能玩转设计模式(所以很多设计模式对于脚本语言来说,都是天生自然而然就能做到的,而不是很难的“编程技巧”)。&
& &&从这个角度来说,java/C#是拥有很强“契约精神”的语言,这种“限制”保证了我们可以在代码量成几何式增长之后仍旧能够保持良好的结构,而且即使是新手,只要按照相应的“契约”,就能够完成上面所交代的任务而不会影响别人的代码。某种意义上来说,java项目更注重“架构”的设计,而Ruby项目更注重个人的编程能力。&
& &&正如黑格尔所说,太阳下面没有新事物,随着我们的项目从无到有,从小到大,代码量成几何式增长,于是我们为了减少重复代码量,将项目中可变的部分抽象出来。为了减少因为代码改动而带来的额外工作量,我们总结了一套设计模式。为了用更少的代码实现总结出来的设计模式,我们将当中公共的部分作为模板(也就是框架),需要用到的时候直接利用这套模板就可以帮助我们专注于业务逻辑的实现而不是其他的条条框框。&
& &&嗯,读到这里的时候,我们已经可以人模人样的做一些项目了,甚至在这个过程中,查看了一些主流框架的使用方法并且用上了他们,我们简直就可以宣称我们是一个合格的软件工程师了!&
& &&其实。。。我们才刚上路。&
& &&进入下面一个应用场景吧!&
& &&@考虑这样一个应用场景:我们已经利用SSH(是的,就是那个很流行的Spring,Struts2,Hbiernate),人模人样的将项目重新搭建起来了,代码的结构瞬间变得无比清晰(虽然我相信百分之八十以上的人并不是真正理解SSH),这个时候,项目变得越来越庞大。。。&
& &&SSH在华人社区流行已久(主要是大陆和台湾地区),其实我个人并不喜欢这三个框架的组合。在欧美地区,只有Spring是依然流行的。(实际上Spring的地位也在遭受很多轻量级IOC框架的挑战)&
& &&在这次的应用场景中,我准备一次性讲述多一点的东西,所以这次的假设会糟糕一点。&
& &&因为开发人员众多,经常会发生每个人的开发环境不一致,比如明明我们用的是Spring 3.0的jar包,却偏偏有人用的是Spring 2.5的jar包。而且项目越做越大,我们不得已分成了几个子项目,交由不同的团队去做,可是经常发生其他团队已经完成了bug
fix并打出新包了,我们仍然在沿用以前的有bug的旧包!&
& &&以前写过一篇关于Maven的简单介绍,这次就直接copy过来了。&
& &&关于构建的概念:&
& &&很久很久之前,在我刚刚学习Java的时候,那个时候还是非常的菜的,有一次学习struts,需要做一个项目,当时的流程是这样的(我相信很多人都时曾相识?):&&
& &&1、熟练地打开eclipse,新建dynamic web项目&&
& &&2、从struts官网下载最新的jar包(好多好多个jar文件啊)&&
& &&3、不管三七二十一,刷的一下,把所有jar包放到WEB-INF/lib&&
& &&4、开始写代码&&
& &&5、右击项目,导出war包,拷贝到tomcat的webapp下&&
& & 这个过程看似没有问题,直到后来实习的时候被项目经理狠批。这个过程中我根本就不知道我所需要的什么jar包,不管有用的没用的,全部放到lib下。这种做法不但会导致lib臃肿难以维护,而且根本无法保证所有开发人员的第三方依赖包版本一致。最关键的是,因为每一次的打包动作,都需要开发人员从eclipse中右击导出war包。想象一种情况:我们的项目中有一个依赖的jar包是另外一个开发小组所写,如果我们需要进行最新的项目测试,我们首先得先让另外一个开发小组将他们最新的代码导出为jar包,
然后将他们最新的jar包导 入我们项目的classpath(这个过程,是不是离开了eclipse大家就不会了?),然后继续,右击导出war包。如果我们依赖的多个jar包都是我们不同的团队所写,这个过程所耗费的时间将成集几何的增长。&
& &&题外话:eclipse导出war包的原理:
& &&我们每次通过eclipse创建dynamic web项目的时候, eclipse会自动帮我们创建一个src文件夹,WebContent文件夹,.project配置文件(其实根据插件的选用,隐藏配置文件会有很多个)。同时引入了一些列classpath:src、
WebContent/WEB-INF/lib、jvm核心依赖包、tomcat中的一些servlet依赖包、其他。。。当我们导出war包的时候,eclipse 首先根据.project中的配置,导入classpath中的依赖包(这也是为什么我们在初学阶段,总是将需要用到的这些jar包放到WebContent/WEB-INF/lib中去),将src下的所有.java文件编译(这也是为什么我们的源代码总是要写在src下才能被编译),将生成的.class文件拷贝到 WebContent/WEB-INF/classes中。最后将WebContent打成war包输出(war包的名字为:项目名.war)。
& &&回来继续:
& &&因为这个过程绝对不可能由人来做(耗费时间太长而且没有意义),于是后来我们就开始学习Ant来进行刚才的操作。Ant的原理就是:指定好我们需要编译的源代码路径(不管一个公司有多少项目,这些项目最新的源代码路径总是有的)、依赖的jar包位置(Ant会帮我们把这些依赖包引入到classpath中)、打包的方式(jar还是war等等之类)、以及打包的顺序(就像最开始所说的那样,可能某一个模块的编译需要依赖另外一个模块,被依赖的源代码会首先被编译)。然后Ant就会帮我们编译这些源代码了,那些被依赖的jar会首先被编译打包(会根据依赖树进行打包顺序),然后放到某个文件夹下,然后这些被依赖的jar包会被引入classpath,然后继续编译,最后,所有的源代码编译结束,将依赖的jar包们拷贝到WEB-INF/lib中,web层的.class们拷贝到WEB-INF/classes中。
删除被打出来放到临时目录 的jar包们。将最后的war包拷贝到指定目录,整个过程就结束了。&
& &&需要说明一下的是:平时我们在eclipse中,eclipse已经帮我们指定了servlet容器位置,所以我们不觉得有什么不对劲,但是一旦自己手动打包的时候,我们必须手动指定servlet相关jar包的路径并引入到classpath中!&
& &&在刚刚的过程中,我们发现,我们可以做到只需要一个命令:Ant自动帮我们根据顺序依次打包最新的代码,然后将最新的代码进行打包,并且可以将生成的war包拷贝到指定目录下,于是我们可以引入一些系统脚本,测试只需要执行一下某个脚本文件,就可以自动的将新鲜出炉的war包放入tomcat/jboss/jetty中,并启动容器。之后什么都不需要做,直接打开浏览器就可以测试啦!&
& &&这个过程之中的问题:
& &&如果你写过Ant的build.xml,也就是Ant的配置文件,你一定会发现这是一个痛苦的过程。首先,我们得指定第三方依赖包的路径,虽然这样能保证所有人引用第三方依赖包的版本一致,但是如果依赖包过多的话,需要编写老长的一段说明。其次,我们需要指定项目源代码的路径,这样是很长的一段说明(同一个项目不一定在同一个地方啊。。。像我之前所说的那样,可能我们项目中的某个模块,是由另一个团队在别的路径下编写,最后我们只是引用他们所生成的jar包而已)。最后,也是最坑爹的事情,我们必须手动指定打包顺序:如果a模块依赖b模块和c模块(这三个模块都是我们自己开发),b模块依赖c模块,我们必须先打包c模块,然后再打包b模块(同时引用c模块打好的包),最后打包a模块(同时引用b模块和c模块打好的包)。这才是最简单的一种情况呀,随着项目的模块化,这种关系可能会变得更加复杂,打包顺序也需要考虑好一会,即使我们很聪明,这种树形顺序难不倒我们,编写xml也是一个很烦人的任务啊。&
& &&Maven的出现:
& &&我们可以简单的认为,Maven也是为了完成上面的任务所诞生的,但是相比较于Ant,我们所需要编写的xml将会骤减不少。而且,在大多数的时候,打包顺序这种费脑经的事,Maven可以依据依赖关系自动帮我们完成。&
& &&同时,Maven不但可以完成了上述Ant所写的所有功能,还有额外的一些功能,帮助我们缩短开发时间:
& &&我们不必再自己去各个第三方依赖包官网手动下载依赖包了,只要申明了我需要某个jar包的某个版本,Maven会自动帮我们下载下来并在编译、打包的时候引用。
& &&Maven贯穿项目整个生命周期,从早期的依赖包下载到后期的打包部署,在编译过程中,找到测试代码,运行jUnit等工具进行测试并生成测试报告。&
& &&Maven比Ant更进一步,更像一个部署工具,依靠插件,可以在运行Maven命令之后,甚至连数据库初始化这个工作都可以帮我们做了,在编译之后,将项目拷贝至容器并启动容器,真正做到“开箱即测”。
& &&Maven的使用:
& &&自行百度吧。。。
& &&Maven的出现实际上是为了适应我们项目越来越复杂,开发人员越来越多,依赖包越来越庞大,同时拆分为更多子项目,打包过程繁琐,自动化测试程度越来越高的发展需要。
& &&我原本觉得下一章应该进入自动化测试的介绍了,但自动化测试绝对是一个无穷无尽的深坑。。。所以我就简单描述一下,在自动化测试中,所有的操作必须由代码来模拟,测试过程中不会有人的干预,所有用例均由代码控制。作为开发人员,我们提供出去的每一个方法都有相应的测试用例,最终会在编译过程中自动由Maven进行测试并生成报告。
& &&进入最后一个应用场景
& &&@考虑这样一个应用场景:有一天我们领导发现,单页面应用变得火爆起来,于是让我们将项目转为单页面应用
& &&首先还是得解释一下什么是单页面应用。
& &&传统的网站在页面上会有各种的超链接以及表单按钮,通过点击这些超链接或者表单按钮,我们会访问不同的网站,如果我们有当当购书的经验,就会知道,当我们点击了购买按钮时,我们会跳转到支付页面,当完成支付时,我们会跳转到购买成功的页面,我们不断地在跳转,也没有觉得有什么不对。
& &&的确,事实上这没有什么不对。
& &&还记得google maps吗?那个超炫的页面,我们在页面上滚动鼠标中论,就可以实现地图的放大和缩小,我们不断地像后台发送请求,后台也一直在反馈,可是至始至终,我们都没有进行过页面的跳转。
& &&这就是ajax,它负责将用户的请求发送到服务端,然后将接收到的返回数据渲染到当前html中。在这过程中,一直都是在早已渲染好了的html中进行操作。
& &&很自然而然的,因为没有页面的全局刷新,我们就像在操纵本地软件那样操作进行操作,正如single app一词,它就像一个app而不是一个网站。
& &&在具体介绍之前,我们先老生常谈一个问题,如何实现MVC?
& &&我去,这个问题在第一个场景中不就已经讲过了吗。
& &&正如下面所见:
& & 由Controller接收请求,将数据封装为 Model 的形式,并将其传入 View 中,毫无难度。&
& & 好吧,不是我侮辱大家智商,只是,很多事情并不是我们想当然的那样,正所谓,世事无绝对嘛。&
& & 我们来看这张图:&
& &&在上图的MVC模式中,我们直接在 HTML(也就是 View)中发送 AJAX 请求,该请求由 Action(也就是 Controller)接收,随后将数据模型转为 JSON 格式返回到 HTML 中。&
& & 早期前端都是比较简单,基本以页面为工作单元,内容以浏览型为主,也偶尔有简单的表单操作,这个时期每个界面上只有很少的JavaScript逻辑。&
& & 随着AJAX的出现,Web2.0的兴起,人们可以在页面上可以做比较复杂的事情了,js针对DOM的操作越来越频繁,于是出现了以简化DOM操作、屏蔽浏览器差异的js库jQuery。(jQuery仅仅是js库,不是框架。。。)&
& & 伴随着一些Web产品逐渐往应用方向发展,遇到了在C/S领域相同的问题:由于前端功能的增强、代码的膨胀,js代码变得越来越混乱。&
& & 于是我们想起了曾经在后台使用过的方法,各种基于MVC变种模式的前端框架应运而生。&
& &&后面真的写不下去了,就这样吧。。。&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:104219次
排名:千里之外
转载:31篇
评论:23条
(3)(18)(1)(2)(6)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 java工作一年工资待遇 的文章

 

随机推荐