软件界面设计尽量简洁明了,功能点击尽量做到一次。
普通的工作站的使用者,给功能提供尽量直接、方便的来回切换、跳转、导航,应当显眼、直接、简约,一步到位。
manager的管理决策用户,他们的时间宝贵,最好设计成傻瓜式的操作,同时,将最关键、最重要的信息,组织、放置在一屏当中。
posted @
2011-08-17 16:48 南山隐士 阅读(188) |
评论 (0) |
编辑 收藏
本原则是本人结合项目的实施开发编写代码情况,对多年以来带领项目实施奋战在开发一线经验的提炼与概括。这十条开发指导原则,最基本的思想是“高效,高质量的写出满足业务功能目标的代码。”每人可以结合当前项目的实际情况应用,可以补充,修订删改进一步总结提炼。
1.先开发简单明确的功能模块,后开发复杂的功能模块。
2.先做简单的子功能,再做稍微复杂的子功能,后开发有难度逻辑复杂的子功能。
3.以满足业务功能要求为主要目标,不保留无用的垃圾代码。写出高质量满足功能要求的代码,是建立在对业务需求理解,明确业务目标,逻辑思路清晰的结果。有时往往需要反复多次修改精益求精才能最后实现客户满意的功能。
4.每开发一个功能模块,都要头脑清晰。(功能目的,界面表现,程序逻辑思路,各层函数调用关系,数据存储),全面系统考虑,力求每个细节都思考一遍,不使疏漏。在一般情况下比葫芦画瓢,充分借鉴一般常用的逻辑代码,业界常用的一般方法,已有类库函数。能够迅速高效写出高质量的一般性代码,以便腾出精力解决关键问题。力求避免功能函数重复开发,代码随意复制,逻辑思路混乱,代码随意修改,瞎写代码。保证所写的每一个函数,每行代码,都有意义,都有目的,坚决删除无用的垃圾代码。这样就保证了,我们写出的代码是简洁的,思路明确的。随着时间的推移,我们写的代码越来越多,就会积累出跟本项目相关的很多通用的类库,函数。通过对比,更能深入的理解业务,抽象出公用的方法,逻辑规范。进而提高整个团队的工作效率。通过循环迭代的思路,不断地扩大成功经验。
5.我们开发程序过程中,总有一些公用的函数类库,可以调用。每次都不是从零开始,不是每行代码都一行一行的手工输入。要充分的利用工具,灵活应用学过的方法。
6.发扬团队协作精神,提高整体测试交叉测试意识,积极总结开发一般性类库函数,提供给大家调用。分享成功经验。避免一个人孤军开发,愁眉苦脸的编写程序。共同攻克业务技术难题,苦中有乐。
7.力求高质量高效的完成开发模块,不要钻牛角尖,经常交流,不懂就问。注意不要把问题复杂化,想当然,自己跟自己制造困难。如果问题越来越复杂,越开发代码越没头绪就立即停止编写,回到问题的原点重新考虑或跟大家交流听听别人的意见。
8,在解决技术问题上,如果是关键问题,坚决研究,要彻底搞明白。与项目相关不影响全局的问题,可以根据实际情况优先级放低一级。针对难点业务复杂的问题,先做外围知识技术准备,找出关键点,先易后难分步骤逐渐深入的去解决。最后将其贯穿成一个整体。
9.经常查看别人代码,吸取别人的经验,充实自己。我们的知识积累主要来自别人,主要在当前项目。取之于别人,受益于自己。受益于项目。
10.善于利用零星时间,比较已经做过的功能模块。不断的整理,优化已经开发过的代码。发现Bug及时修正,精益求精。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhaoyu_1979/archive/2011/03/16/6254021.aspx
posted @
2011-03-23 16:45 南山隐士 阅读(220) |
评论 (0) |
编辑 收藏
一相关下载
(1) java JDK下载:
进入该网页: http://java.sun.com/javase/downloads/index.jsp (或者直接点击下载)如下图:
选择 Download JDK 只下载JDK,无需下载jre.
(2)eclipse下载
进入该网页: http://www.eclipse.org/downloads/ (或者直接点击下载:BT下载 HTTP下载) 如下图:
我们选择第一个(即eclipse IDE for java EE Developers)
(3)下载Android SDK
说明: Android SDK两种下载版本,一种是包含具体版本的SDK的,一种是只有升级工具,而不包含具体的SDK版本,后一种大概20多M,前一种70多M。
完全版下载 (android sdk 2.1 r01) 升级版下载 (建议使用这个,本例子就是使用这个这里面不包含具体版本,想要什么版本在Eclipse里面升级就行)
二 软件安装
(1)安装jdk 6u19 安装完成即可,无需配置环境变量
(2)解压eclipse eclipse无需安装,解压后,直接打开就行
(3)解压android sdk 这个也无需安装,解压后供后面使用
(4)最终有三个文件夹,如下图:
三 Eclipse配置
1 安装android 开发插件
(1)打开Eclipse, 在菜单栏上选择 help->Install New SoftWare 出现如下界面:
点击 Add按钮,出现如下界面
输入网址: https://dl-ssl.google.com/android/eclipse/ (如果出错,请将https改成http)
名称: Android (这里可以自定义)
点击OK,将出现如下界面
点击 Next按钮 ,出现如下界面:
点击Next按钮,出现如下界面:
选择 I accept the terms of the license agreements 点击Next,进入安装插件界面
安装完成后,出现如下界面
点击Yes按钮,重启Eclipse
2 配置android sdk
(1)点击菜单window->preferences,进入如下界面
选择你的android SDK解压后的目录,选错了就会报错,这个是升级工具,目前还没有一个版本的SDK
(2)升级SDK版本,选择菜单 window->Android sdk and avd manager 出现如下界面
选择update all按钮,出现如下界面
选择左边的某一项,点击accept表示安装,点击reject表示不安装,我这里只选了SDK 2.1 和samples for api 7 , 自己可以任意自定义,确定后,选择install按钮,进入安装界面如下:
安装完成如下:
(3)新建AVD(android vitural device) 和上面一样,进入android sdk and avd manager,选中Vitural Devices 在点击New按钮
点击New按钮后,进入如下界面:
名称可以随便取,target选择你需要的SDK版本,SD卡大小自定义,点击 Create AVD,得到如下结果
如上显示创建AVD完毕
3 新建Android项目
(1)选择菜单file->new->other 进入如下界面:
选择新建Android Project项目,点击Next按钮,进入如下界面
名称自定义,应用程序名自定义,报名必须包含一个点以上,min SDK version里面必须输入整数
点击Next出现如下界面:
注: 若有错误如: Project ... is missing required source folder: 'gen' ,则将gen->Android.Test->R.java这个文件删掉,Eclipse会为我们重新生成这个文件,并且不会报错。
(3)配置运行
右键项目->Run as -> Run Configuration 进入如下界面:
该界面,点击Browse 按钮,选择你要运行的项目
选择Target切换到以下界面
该界面选择运行的AVD,将AVD前面的方框设置为选择状态。
(4)测试项目运行
右键项目名称->run as ->Android Application 即可启动运行该Android程序,如下所示:
正在进入
测试程序运行结果
四 结束语
至此,android开发环境搭建完毕,有问题请留言。在这里要注意,我这里只是下载了android sdk r4升级工具,没有下载具体的SDK,而是通过在Eclipse里面的Android Sdk管理工具升级的,你也可以直接下载具体的SDK版本,如: Android sdk 2.1 r1 上面有这个的下载链接,但我任务用升级工具更好。
posted @
2010-07-13 14:35 南山隐士 阅读(625) |
评论 (0) |
编辑 收藏
建立一个Silverlight项目,添加一个子窗口ChildWindow1.xaml.
在子窗口设计中添加一个输入框:<TextBox x:Name="txtUserInfor" Grid.Row="0" />
添加子窗体的CS代码:
string testString;
public string TestString
{
get { return testString; }
set { testString = value; }
}
增加一个事件: public event EventHandler OkClicked;
修改OKButton_Click方法:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
if (OkClicked != null)
{
TestString = txtUserInfor.Text;
OkClicked(this,new EventArgs());
}
this.DialogResult = true;
}
子窗口修改完毕。
父窗体:
设计中添加一个输入框和一个Button:
<TextBox x:Name="tbInfo" Width="100" Height="50"></TextBox>
<Button Click="Button_Click" Width="100" Height="60" Content="子窗口测试" HorizontalAlignment="Right"></Button>
修改父窗体代码:
public FatherControl()
{
InitializeComponent();
childWindowDemo.OkClicked += new EventHandler(childWindowDemo_OkClicked);
}
void childWindowDemo_OkClicked(object sender, EventArgs e)
{
tbInfo.Text = childWindowDemo.TestString;
}
private ChildWindow1 childWindowDemo = new ChildWindow1();
private void Button_Click(object sender, RoutedEventArgs e)
{
childWindowDemo.Show();
}
完毕。
运行,点击父窗体按钮,弹出子窗体。在子窗体的输入框中输入内容,点击确认后关闭子窗体,同时子窗体的数据更新到父窗体的输入框中。
posted @
2009-12-11 09:56 南山隐士 阅读(1020) |
评论 (1) |
编辑 收藏
可以总结为两大关键点:一是养成好的编程习惯,二是针对自已的工作提高自已的知识含量.
一. 好的编程习惯
1. 写程序前打个草稿可以在心里,最好在纸上:目的要从整体上考虑程序的实现。
如果公司采用建模的方式,有建模工具(rose ,visio )那是最好不过的了。
2. 注意休息,不要浪费自已的休息时间,用去了自已的时间不但会写出的代码因为注意力不集中而会常常出现代码的质量有问题,逻辑常出错
3. 要善于收集相关的专业开发上的资料,以便以后能更快更好的解决问题目。提倡公司能提供内部知识勾通的工具(如知识论坛,内部即时聊天器);提倡公司内部有技术资料的共享库,提高解决问题的能力.
4. 提高对所写的模块的相关全局把握能力,在写程序中要最好先详细设计后再发布.
5. 要学会与他人沟通如非工程师,学会沟通的不同方式,提高沟通的效率。
二. 不同的目标不同的知识重点
(一) 目标:程序员
职责:根据详细设计文档,或根据高级程序员的设计进行相关的开发。
1. 要学会看相关的需求文档及详细设计文档。
注意:你必须要通过阅读这些文档把握住其中的重点,关键点,相关易漏点
2. 如果公司里会用UML来相互的沟通,这时你必须要深刻理解UML 的相关知识,一定要注意千万不要对UML图一知半解的情况下,就着写代码,那样会错的很惨。
3. 学好对应的计算机语言的基础知识,如:程序的语法,关键点,易错点,对应的出错如何出理,如何才能把对就的程序写的键壮一些
4. 如果用到数据库的内容,在学会sql的前提下,尽量学会数据库原理中的相关sql内容, 当然为了提高查询的能力也可以增加一点
5. 如果用到面向对像的语言那最好学点相关的设计模式,这样的可以增加代码的扩展性,及可维护性等,能够理解详细设计中的模块间的设计原则这个也可以提高对模块的内容编写的正确性.
6. 你一定要学会公司内部的通用的编码规范。
7. 学习如何做单元测试比较好.必须要熟悉相关的单元测试工具.
8. 要不断的对相关知识进行总结,同时也要必须把相关的资料进行整理和学习,在学习过后的资料中你可以在遇到问题时更快的找到问题的答题。
9. 在开发你必须记录下大家常出错的地方及大家的解决方法,这个对你以后错误的避免有很大的作用.
10. 在写代码中时必须把上面写过代码记在心里,这样就可以养成习惯,提高代码的速度
11. 对数据库操作时,要尽量共用Connection,并小用以减少Connection的数量
(二) 目标:高级程序员
职责:对需求文档进行系统相关模块的详细设计,并负责对程序员的支持及指导和相关核心模块的编写
所以不但要学会相关程序员要的知识,同时还要学会难度比较大的知识。
1. 程序员的知识,如设计模式你一定要不是简单的看要懂,你还要应用设计模式对相应的模块进行相关的详细设计。
2. 要学好相关详细设计的工具做的有的放矢,这样可以更好提高对自已的设计的表达
3. 为了提高系统的运行效率会运用到
a. 数据库的表结构如何建才能使应用的要查询sql 更快。这时可要认真认真的学习一样数据库原理,千万不要以为采用数据库的范式越高系统的运行效率会越好,有时候适当的表冗余可以大幅度的提高系统的查询效率. 同时适当的建索引,视图,存储过程也是提高系统对数据库的查询的效率之一。
b. 学习多线程的编程,不过千万不要以为线程数越多运行的速度会越快,一般线程的数量超过一定的数量后,系统的运行速度反而会变慢。为了应用好多线程,操作系统这本书也要关于同步及相关进程和线程的知识必不可少。
c. 设计好的一程序的好的算法,可要比起解一道同一复杂的数学题,要难的多,所以要在学好的相关数学的知识上(如线性代数,离散数学,概率论,数理统计)。更要深入计算方法,及数据结构,让数学问题用计算机来解决。
4.为了让系统设计的更加的可扩展性,稳定性,设计模式和软件工程可是不能少的东西。所以必须把设计模式用于模式级的设计.
5. 如果公司采用的是Rose (UML)进行设计的话,你对于UML 的理解一定要非常的准确,同时你要跟小组中的程序之间进行充分的UML概念上及对应用例图,类型图,对象图,协作图的意思多写一些注释加深大家对你的设计上的理解。
(三) 目标:系统分析员
职责:做好与客户之间的关系,同时对客户的需求要正确的理解,要选择合适的开发技术,同时做好与客户间沟通交流,学会说服对方。
1. 学会对客户的沟通:要正确理解客户的需求同时要保证相互之间的沟通顺畅。
2. 对了解来的需求要能用笔正确的描述下来,并能很好的传叙给其他人。这时要学会用如ROSE 等的软件建模的工具。和powerdesign等的数据库建模工具。和相关的UML,数据流程图及相关的内容的知识。
3. 不但要全面的了解客户的需求而且还要对需求进行未来的可能的改变要有相当多的了解。
4. 全面的了解客户的需求后,要选择合适的相关技术用于开发,:
这时要学习各种知识
a. 先择数据库:db2,infomix ,oracle ,sql server,mysql 的优缺点,可以从中选择最适合的数据库及理由。
b. 设计数据库:要扎实在数据库的理论(数据库原理,数据库系统设计)及相关数据库设计经验,要尽量多的分析过去数据库设计,分析这么设计数据库的好处。这时可能要用到 powerdesign等工具。
c. 写需求说明文档和概要设计文档,同时要学会要分析相关需求说明文档的需要的内容的相关知识,如人员工时的计算方法, 一般会用 project 来分析相关的项目的内容。
d. 选择合适的程序语言及相关的架构,一般主流的架构是 J2EE和.net的相应的优点及它们之间的结合,如采用soap xml进行相关的结合,或用java-com 桥 进行相关的功能的调用。和它们之间的相关语言优缺点
e. 还要根据b/s,c/s 结构对开发的网络影响的相关内容采取选择。
5. 学会说服对方,毕竟客户都不是个个是软件专家,他们的选择有时未必是正确的所以学会说服对方,是系统分析员必备的能力条件.
三. 训练的方法:
1. 计划行事:
(1 设定你的未来的学习目标
a. 未来要成为什么样的人(主要是工作角色,如程序员,高级程序员,系统分析员)
b. 你近期要成为什么样的人(当前的工作职责是什么,如果只写代码是程序员等)
c. 要完成近期的工作所必须要知识(如java 程序员,要学习java 基础知识,等),关键的知识(如java中关键要用到的知识有,面向对象等),易错的知识(比较原来的已有知识进行合对)
(2 设定你的学习目标后,并要有针对性的对应目标设定学习时间的按排及学习路线。并直观的记录在案,以便以后随时核对,
(3 常常抽出一定的时间认真核对计划的完成情况,如果没有按时完成计划的内容。分析原因,尽量想法赶上计划内容如果存认是计划有误,要认真总结计划失败出错的原因,对你的未来有很大的帮助。
注意:不要对计划的按排过于乐观 要尽量的考虑实现中的各种情况,同时适当按排一些缓冲时间,以便真正能按照计划行事,以提高按计划行事信心,同时这能有效避免出现计划中途成没有意义的东西。
2. 针对工作角色对自已的能力进行培养和知识进行学习。
关键的能力:
(1. 记忆能力:要学会把自已的写的代码和改的代码记的清清楚楚。要能提高效率。
(2. 逻辑思维能力:要多多的看别人的复杂逻辑的代码,分析复杂逻辑的运算。
(3.全局能力: 不要再范改了东,却西出错。(构造软件这个很重要)
(4.学习能力: 并不是每个项目都你是所熟悉的项目的,并不是每个项目中的知识你都知道,要掌握最新的技术和最有用的知识,是最关键的。要学会,提高能力,这个东西是永远对自己有好处的。
(5. 沟通能力; 学会幽默,学会讲故事,学会交朋友,学会礼节。
(6.自制能力:如果一个人不能自制那这个人以后,不会有很大成果,即使很大机会发展起了,可是因为没有自制能力很容易被人利用,或自己明明知道怎么做,可是就是不能控制自己的欲望.而常做下无法挽回在错误.
四. 例:java 程序员的知识结构及学习流程:
(一) 学习相关工作必须的知识
1.Java 语言的基础(推荐书:《 java 编程思想》)
关键:
(1. java 面向对象及对应的程序现实
(2. java 多线程
(3. java 网络 socket
(4. 应用界面
2.学会用智能集成开发工具jbuilder,eclipse等一种,根据资料里的内容,自已写与例程类似的代码,但注意不要直接抄它,一定要自已写。同时最好写到一个工程中以便对比。
3.如果用b/s结构要学习jsp的知识(推荐书:《 JSP 2.0技术手册 》)
关键:
(1. 界面处理:
a . HTML——超文本标志语言:用于显示页面如:超文本链接, 表格,各种标志等。
b. CSS———层叠样式表:控制正文外观的一组格式.用于美化HTML页面。
c. javaScript—嵌入HTML页面浏览器来执行的脚本语言:让页面可以根据用户的操作或事先设置等在客户端进行动态变化,而且不需传回服务器。比如: 对表单输入的正确性做客户端验证.
(2.jsp元素:如java代码写法,对应标志---jsp:include,jsp:useBean,jsp:setProperty,
jsp:getProperty等.jsp的几大对
(3. javaBean及其在jsp 中的调用和相关应用.
(4. 其他技术:
a. 如何操作数据库—用jdbc(可能要补充一些数据库的知识,如oracle ,sql server,
包括如何写高效率的查询sql,存储过程等) ,
b. 如何发送email—用javaMail,
c. 如何学习如何用实现文件的上传下载,如果操作文件,
d. 如何操作xml --用jdom 及 jaxp(这时有必要学习一下xml 的语法如 dtd等)
e. 如何远程方法调用—用 rmi
f. 如何进行消息服务 ---用 jms
5.再有些公司会用到 J2EE 的架构如 EJB 作为业务逻辑.
(1.EJB中要分清
(2. struts MVC
(3. Hibernate 操作数据库
6.最好学习一下UML
学用Rose建模
五 忠告:
1. 不要以为自已很差,要明白每个人都是这样一步一个脚印的走过来的。(我们要有信心)
告诉自已:比尔盖次,也是同我们一样,出生时也是巴掌大.
我们只有多学,多练才可能有出路.
2. 不要以为自已学的多就很强,世界上的高手多的是,问问自己,你每小时可以写几行代码,代码一次写下来有多少错误,如果你一次写下没有错误,一小时可以写1000代码,那才是真正的高手.
3 . 不要以为自已没有项目做就会落后于他人,人家是参加了很多项目,可是人家只是项目中的一个小角色,如果我们在空时能都写一些开源的项目,或自己开发和设计一些有用的开源的项目,水平及能力很快就上来了.
4. 不要以为自己做过很多的项目就很了不起了。你能说你做的项目中,你能体会整个项目为什么要这样设计,为什么要这样开发吗?相信绝大多数是否定的回答。那还不如多学习一些已做的项目,了解他们为什么要这么做,为什么这么开发,多看一下它们的项目的文档,我们能明白很多,这样把他们的经验放于你未来可能要接手的项目,这样不是更好吗?
5. 不要以为自己的学习能力很牛,你能快速阅读一本书又能快速掌握它的内容吗
posted @
2008-12-11 19:12 南山隐士 阅读(259) |
评论 (0) |
编辑 收藏
Acegi + Spring + Hibernate + Struts 2搭建基于角色的权限控制系统
安全永远是WEB应用系统必须面对的头等大事, 也是最头疼的事, 其实安全系统就只包括两个问题: 认证和授权. 以前做些网站系统, 安全检测逻辑都在放在须要安全控制的代码前面, 这样做有很多不好的地方, 重复多次的编码就不用说了, 代码移植性, 重用性都得不到体现, 安全检测逻辑要永远和业务逻辑放在一起.
那么, 能不能够在进入方法前就调用一些安全检测? 其实Spring AOP就是这个思想, 那么又如何实现安全检测呢? Spring Acegi Security 框架就是做这个事情.
本文主要是讨论下在已有的SSH系统中, 如何使用Acegi作为安全框架实现基于角色的权限控制(Role Based Access Control RBAC) , 本文主要是以Java 5注解的形式来配置安全框架, 大大减化配置和操作.
本文的主要参考资料: <Spring 2.0 核心技术与最佳实践> 第10章 (Spring Acegi 安全框架)
<精通Spring 2.X -- 企业应用开发详解> 第17章 (使用Acegi 实施应用系统安全)
acegi-security-1.0.6 官方文档
说明: 本文介绍的是RBAC, 在官方文档的基础上有所扩展或改动, 以更适合WEB应用系统. 其实我觉得大多数的网站基于角色已经足够了, 一般都没必要基于权限.
文章开始:
一. 下载所要的软件或JAR包:
我的相关配置是: Java 5, Tomcat 5.5.26, Struts 2.0.11, Spring 2.5.1, Hibernate 3.2, Acegi 1.0.6
二. 建立相关的数据库:
数据表: 用户信息表User: id, enable, user_name, user_pass, email_box
角色信息表RoleInfo: id, role_name, role_title, descp
用户与角色关联表(用户与角色是多对多关系)UserRole: user_id, user_name, role_id, role_name
并在这三个表中插入相关的数据, 我是定义了两种角色(role_name): ROLE_USER, ROLE_ADMIN
和三个用户, 一个用户角色为: ROLE_USER, ROLE_ADMIN
另一个用户角色为: ROLE_USER
第三个没有角色.
二. 修改配置文件:
其实对Acegi框架的应用难点就在配置文件, 所以要特别注意了:
在 src 建立Acegi的配置文件: acegi-security.xml 当然这个文件的名称是可以任意的.
acegi-security.xml 说白了就是配置: 安全拦截器, 认证管理器, 决策管理器.
其内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 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.xsd">
<!-- ========================= 认证管理器 ========================= -->
<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="daoAuthenticationProvider" />
<ref bean="rememberMeAuthenticationProvider" />
</list>
</property>
</bean>
<!-- 基于DAO验证的AuthenticationProvider -->
<bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="userDetailsService" class="org.ymcn.security.AcegiUserDeitailsService">
<property name="userDao" ref="userDao" />
<property name="userRoleDao" ref="userRoleDao" />
</bean>
<bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="obullxl@163.com" />
</bean>
<bean id="rememberMeServices" class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService" ref="userDetailsService" />
<property name="parameter" value="j_remember_me" />
<property name="key" value="obullxl@163.com" />
<property name="tokenValiditySeconds" value="31536000" />
</bean>
<!-- ========================= 决策管理器 ========================= -->
<bean id="accessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleVoter" />
</list>
</property>
<!-- 是否全部弃权就通过 -->
<property name="allowIfAllAbstainDecisions" value="false" />
</bean>
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
<property name="rolePrefix" value="ROLE_" />
</bean>
<!-- ========================= 过滤器链 ========================= -->
<bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,rememberMeFilter,exceptionFilter,securityInterceptor
</value>
</property>
</bean>
<bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<!-- 登录退出后的URL -->
<constructor-arg value="/" />
<constructor-arg>
<list>
<ref bean="rememberMeServices" />
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
</list>
</constructor-arg>
<!-- 登录退出的URL -->
<property name="filterProcessesUrl" value="/j_logout.j" />
</bean>
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<!-- 登录失败后的URL -->
<property name="authenticationFailureUrl" value="/login.jsp?msg=%E6%97%A0%E6%95%88%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%E6%88%96%E5%8F%A3%E4%BB%A4" />
<!-- 登录成功后的URL -->
<property name="defaultTargetUrl" value="/user/cmd.jsp" />
<!-- 登录的URL -->
<property name="filterProcessesUrl" value="/j_login.j" />
<property name="rememberMeServices" ref="rememberMeServices" />
</bean>
<bean id="rememberMeFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="rememberMeServices" ref="rememberMeServices" />
</bean>
<bean id="exceptionFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<!-- 出现AuthenticationException时的登录入口 -->
<property name="authenticationEntryPoint">
<bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/login.jsp" />
<property name="forceHttps" value="false" />
</bean>
</property>
<!-- 出现AccessDeniedException时的Handler -->
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/denied.jsp" />
</bean>
</property>
</bean>
<bean id="securityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/admin/**=ROLE_ADMIN
/user/**=ROLE_USER
/cart/previeworder*=ROLE_USER
</value>
</property>
</bean>
</beans>
在上面的配置文件中, 红色部分要特别注意, 其余的内容都差不多了.
<bean id="userDetailsService" class="org.ymcn.security.AcegiUserDeitailsService">
<property name="userDao" ref="userDao" />
<property name="userRoleDao" ref="userRoleDao" />
</bean>
在整个应用的安全控制中, 我们唯一要编写代码的类就是: org.ymcn.security.AcegiUserDeitailsService
就连登录和登出的代码也不要了.
三. 修改 web.xml, 增加安全控制过滤链.
<filter>
<filter-name>acegiFilterChain</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>acegiFilterChain</filter-name>
<url-pattern>*.j</url-pattern>
</filter-mapping>
注意: 这个过滤器一定要在MVC转发过滤器的前面!!!!
四. 在 applicationContext.xml 中增加 Acegi安全控制拦截器 和 Spring的自动代理功能实现AOP代理
<!-- Acegi安全控制拦截器 -->
<bean id="serviceSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="validateConfigAttributes" value="true" />
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="objectDefinitionSource">
<bean class="org.acegisecurity.intercept.method.MethodDefinitionAttributes">
<property name="attributes">
<bean class="org.acegisecurity.annotation.SecurityAnnotationAttributes" />
</property>
</bean>
</property>
</bean>
<!-- 利用Spring的自动代理功能实现AOP代理 -->
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
<value>serviceSecurityInterceptor</value>
</list>
</property>
<property name="beanNames">
<list>
<value>userService</value>
<value>mailService</value>
</list>
</property>
</bean>
五. 编写在利用Acegi框架唯一要我们编写的类 AcegiUserDeitailsService.java
package org.ymcn.security;
import java.util.List;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.ymcn.dao.UserDao;
import org.ymcn.dao.UserRoleDao;
import org.ymcn.model.User;
import org.ymcn.model.UserRole;
public class AcegiUserDeitailsService implements UserDetailsService {
private final Log LOG = LogFactory.getLog(AcegiUserDeitailsService.class);
/* 依赖注入 */
private UserDao userDao;
private UserRoleDao userRoleDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setUserRoleDao(UserRoleDao userRoleDao) {
this.userRoleDao = userRoleDao;
}
/* 用户所有的权限 */
//private final List<GrantedAuthority> grantedAuthList = new ArrayList<GrantedAuthority>(6);
private GrantedAuthority[] grantedAuthArray;
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
if(LOG.isDebugEnabled()) {
LOG.debug("Loading UserDetails of userName: " + userName);
}
/* 取得用户 */
User user = userDao.getUserByName(userName);
if(user == null) {
LOG.warn("UserDetails load failed: No such UserRole with userName: " + userName);
throw new UsernameNotFoundException("User name is not found.");
}
/* 取得所有用户权限 */
List<UserRole> userRoleList = userRoleDao.getUserRoleByUserName(userName);
if(userRoleList == null || userRoleList.size() == 0) {
LOG.warn("UserRole load failed: No such UserRole with userName: " + userName);
throw new UsernameNotFoundException("UserRole is not found.");
}
/* 取得用户的所有角色 */
int size = userRoleList.size();
grantedAuthArray = new GrantedAuthority[size];
int j = 0;
for(int i = 0; i < size; i++) {
UserRole userRole = userRoleList.get(i);
if(userRole != null) {
this.grantedAuthArray[j++] = new GrantedAuthorityImpl(userRole.getRoleName().toUpperCase());
}
}
LOG.info("UserName: " + userName + " loaded successfully.");
return new org.acegisecurity.userdetails.User(userName, user.getUserPass(),
true, true, true, true, this.grantedAuthArray);
}
}
六. 在业务逻辑代码中利用Java 5注释实现安全控制
@Secured({"ROLE_USER"})
void sendSimpleMail(Long userId);
@Secured({"ROLE_ADMIN"})
void sendAttachmentMail() throws Exception;
其实就是在需要安全控制的方法前加上: @Secured({"角色名"}), 非常的简单
七. 整个工作完成
Acegi框架完全是一种可插拔式的, 完全可以在原有的系统中加个一个配置文件, 和在每个方法前加上: @Secured({"角色名"}) 就可完成.
上面的 AcegiUserDeitailsService.java 中的有 UserDao, UserRoleDao, 我想一看就知道它们是干什么的了, 这完全取决于个人的实现, 与Acegi无关, 它仅仅只要返回一个 return new org.acegisecurity.userdetails.User(userName, user.getUserPass(),
true, true, true, true, this.grantedAuthArray) 就可以了.
|
posted @
2008-12-11 18:51 南山隐士 阅读(683) |
评论 (0) |
编辑 收藏
上个世纪90年代中期,为了推进我国企业管理信息化,寻求更大的企业发展空间,一批具有一定规模的财务软件公司纷纷转向企业管理软件,大量冠名为某某管理的软件产品迅速涌现,同时国际管理软件巨头纷纷抢滩国内市场,在这些软件企业的大力推动下,我国企业界开始广泛了解管理软禁先进性,2004年-2005年,管理软件开始成为市场迅速增长的需求,国内众多公司开始使用管理软件成为一种趋势。
但是,现在回过头看来,真正成功、成熟的管理应用案例在中国市场仍然凤毛麟角。
目前市面上,叫“管理软件”的成千上万,很多的管理软件,他们的界面、输入、操作是那么的千篇一律,这类软件,开发就是搭积木,装配的痕迹太重,没有个性。有专家指出,管理思想很难“落地”的核心原因就在于对信息层次管理的认识的缺失或不足,往往被意识层次中的一种习惯性思维--试图用思想让思想“落地”所束缚,而现实中,阻碍管理思想“落地”的核心问题,恰恰更多的都集中到信息层次的管理问题上了。所以,要想真正让管理思想“落地”,我们管理者必须跳出意识层次来看问题,并采用信息层次的管理手段来进一步解决问题。
从这里我们不难发现,问题的根源就在于没有把管理思想真正通过信息化落实下去。很多管理软件应用企业,仅仅只是把管理软件当做一个统计或者发发信息的工具。
而用户真正需要的是解决企业在经营管理中遇到的问题,而这些问题的解决需要一个从单项产品到整合应用的发展过程。我国企业最初的需求是财务管理、进销存管理,这已经在前些年的财务软件发展浪潮中得到普及。我国企业现在的需求,是面对着工业化改革与信息化颠覆的双重革命,需要利用最少的成本代价,将旧的系统迁移到新的平台上,从而适应网络经济和电子商务带来的供应链管理、客户关系管理等领域的时代变化。我国企业未来的需求,是将企业内外资源的管理纳入到统一的符合我国特色国情的管理平台之上,彻底改造企业管理体制和机制。
我们国家的管理软件,这么多年来最缺的是管理思想和管理方法,没有科学的管理模型作为支撑,管理软件是不能称之为“管理软件”的。因为管理软件的核心不在于软件技术本身,而是在于管理思想的问题。
一位业内资深人士就说了:“我们国家十几年来管理软件产业的发展,最致命的问题就出在这个地方,我们很多的软件公司、很多编程人员不懂管理,不知道企业的管理问题是什么,更不知道解决这些问题的管理思想和管理模型是什么,他们开发出来的“管理软件”,当然也就不能真正帮助企业解决管理问题。”这种“管理软件”充斥着市场,客户的普遍不满意也就是情理之中的事情了。
管理软件是用来解决管理问题,其关键在于管理的思想和方法。可以说,管理思想和方法是管理软件的灵魂。今天,我们很多人仍然以为管理软件门槛很低,大学毕业出来就能做,只要会编程的人员就能做。开发管理软件产品,必须先把要解决的管理问题研究清楚,把解决这些问题的管理方法和管理模型的研究清楚,然后再开发软件产品。
前沿的软件技术、独特的行业业务模型加上科学的管理思想和方法,三者的创造性融合,才有可能产生一个真正能创造客户价值的管理软件产品。著名的金和软件产品一直被业界称为“有思想的软件”,关键在于金和软件对协同管理软件的准确定位,以及为客户带来真正的价值。众所周知,无论前端OA系统还是后端ERP等业务系统,都是遵循固定流程的,产品之间并无明显的差异,但是在这两者之间的协同领域,却存在很高的准入壁垒。金和软件创造性地发挥独创的精确管理思想和协同理念优势,以产品、工具和行业解决方案为基础,构建了适合各个行业的协同管理平台。
协同企业是现代企业运营的高级状态,企业作为一个整体,一定是一个协同的系统,有效的协同决定了企业的经营效率、达成目标的能力、资源的有效利用以及企业核心能力。金和C6的设计完全符合这种柔性的企业协同理念。协同企业的主要基础是企业流程和知识系统,它们本身是刚性的和持续积累的,但是以此为基础的协同管理平台却是整合的、柔性的,通过长期的应用和优化,最终使企业的协同能力不断提高,真正成为协同企业。
作为国产软件企业的责任之一,不能仅仅是销售软件,更重要的是交给企业一把“利剑”。这就要把先进的技术和先进的管理思想一起交给企业。仅仅“把软件用起来”或“提高工作效率”并不是最终目的,只有通过管理思想的落实,真正提高了企业的管理水平,才是实施管理软件系统的真实目标。在当前的管理软件市场中,过分强调技术含金量以突出产品的先进性也是一种不良的倾向。
管理软件的开发设计上,必须具体两个条件:一是对业务流程的深刻理解;二是设计者所具备的能力。只有好的理解,在软件设计上没有可供操作的控件,就不能随心所欲的去实现设计的初衷,表现在使用上,则是让用户改变它们过去的工作习惯和方式。对于管理软件领域而言,如果不能将先进的技术通过先进的管理思想把企业用户的应用实际统一起来,再高的技术含金量也只能是事倍功半。技术与应用的融合,其目的是贯彻一种核心管理思想,其目的是帮助企业实现体制机制创新。建设信息交流完备的组织系统,确立供应链管理的核心地位,全面拓展客户关系管理,最终实现企业的资源整合。
经历了十年风雨,我们有理由相信,跨入新世纪的我国企业管理软件市场将能更为准确地把握各类管理软件的精髓,解开中国管理软件发展症结,最终推动企业管理进步,促进整个市场朝着健康、有序和独立的方向蓬勃发展。
posted @
2008-08-27 13:38 南山隐士 阅读(165) |
评论 (0) |
编辑 收藏
一、安装篇
jspSmartUpload是由www.jspsmart.com网站开发的一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中。该组件有以下几个特点:
1、使用简单。在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载,方便。
2、能全程控制上传。利用jspSmartUpload组件提供的对象及其操作方法,可以获得全部上传文件的信息(包括文件名,大小,类型,扩展名,文件数据等),方便存取。
3、能对上传的文件在大小、类型等方面做出限制。如此可以滤掉不符合要求的文件。
4、下载灵活。仅写两行代码,就能把Web服务器变成文件服务器。不管文件在Web服务器的目录下或在其它任何目录下,都可以利用jspSmartUpload进行下载。
5、能将文件上传到数据库中,也能将数据库中的数据下载下来。这种功能针对的是MYSQL数据库,因为不具有通用性,所以本文不准备举例介绍这种用法。
jspSmartUpload组件可以从www.jspsmart.com网站上自由下载,压缩包的名字是jspSmartUpload.zip。下载后,用WinZip或WinRAR将其解压到Tomcat的webapps目录下(本文以Tomcat服务器为例进行介绍)。解压后,将webapps/jspsmartupload目录下的子目录Web-inf名字改为全大写的WEB-INF,这样一改jspSmartUpload类才能使用。因为Tomcat对文件名大小写敏感,它要求Web应用程序相关的类所在目录为WEB-INF,且必须是大写。接着重新启动Tomcat,这样就可以在JSP文件中使用jspSmartUpload组件了。
注意,按上述方法安装后,只有webapps/jspsmartupload目录下的程序可以使用jspSmartUpload组件,如果想让Tomcat服务器的所有Web应用程序都能用它,必须做如下工作:
1.进入命令行状态,将目录切换到Tomcat的webapps/jspsmartupload/WEB-INF目录下。
2.运行JAR打包命令:jar cvf jspSmartUpload.jar com
(也可以打开资源管理器,切换到当前目录,用WinZip将com目录下的所有文件压缩成jspSmartUpload.zip,然后将jspSmartUpload.zip换名为jspSmartUpload.jar文件即可。)
3.将jspSmartUpload.jar拷贝到Tomcat的shared/lib目录下。
二、相关类说明篇
㈠ File类
这个类包装了一个上传文件的所有信息。通过它,可以得到上传文件的文件名、文件大小、扩展名、文件数据等信息。
File类主要提供以下方法:
1、saveAs作用:将文件换名另存。
原型:
public void saveAs(java.lang.String destFilePathName)
或
public void saveAs(java.lang.String destFilePathName, int optionSaveAs)
其中,destFilePathName是另存的文件名,optionSaveAs是另存的选项,该选项有三个值,分别是SAVEAS_PHYSICAL,SAVEAS_VIRTUAL,SAVEAS_AUTO。SAVEAS_PHYSICAL表明以操作系统的根目录为文件根目录另存文件,SAVEAS_VIRTUAL表明以Web应用程序的根目录为文件根目录另存文件,SAVEAS_AUTO则表示让组件决定,当Web应用程序的根目录存在另存文件的目录时,它会选择SAVEAS_VIRTUAL,否则会选择SAVEAS_PHYSICAL。
例如,saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)执行后若Web服务器安装在C盘,则另存的文件名实际是c:\upload\sample.zip。而saveAs("/upload/sample.zip",SAVEAS_VIRTUAL)执行后若Web应用程序的根目录是webapps/jspsmartupload,则另存的文件名实际是webapps/jspsmartupload/upload/sample.zip。saveAs("/upload/sample.zip",SAVEAS_AUTO)执行时若Web应用程序根目录下存在upload目录,则其效果同saveAs("/upload/sample.zip",SAVEAS_VIRTUAL),否则同saveAs("/upload/sample.zip",SAVEAS_PHYSICAL)。
建议:对于Web程序的开发来说,最好使用SAVEAS_VIRTUAL,以便移植。
2、isMissing
作用:这个方法用于判断用户是否选择了文件,也即对应的表单项是否有值。选择了文件时,它返回false。未选文件时,它返回true。
原型:public boolean isMissing()
3、getFieldName
作用:取HTML表单中对应于此上传文件的表单项的名字。
原型:public String getFieldName()
4、getFileName
作用:取文件名(不含目录信息)
原型:public String getFileName()
5、getFilePathName
作用:取文件全名(带目录)
原型:public String getFilePathName
6、getFileExt
作用:取文件扩展名(后缀)
原型:public String getFileExt()
7、getSize
作用:取文件长度(以字节计)
原型:public int getSize()
8、getBinaryData
作用:取文件数据中指定位移处的一个字节,用于检测文件等处理。
原型:public byte getBinaryData(int index)。其中,index表示位移,其值在0到getSize()-1之间。
㈡ Files类
这个类表示所有上传文件的集合,通过它可以得到上传文件的数目、大小等信息。有以下方法:
1、getCount
作用:取得上传文件的数目。
原型:public int getCount()
2、getFile
作用:取得指定位移处的文件对象File(这是com.jspsmart.upload.File,不是java.io.File,注意区分)。
原型:public File getFile(int index)。其中,index为指定位移,其值在0到getCount()-1之间。
3、getSize
作用:取得上传文件的总长度,可用于限制一次性上传的数据量大小。
原型:public long getSize()
4、getCollection
作用:将所有上传文件对象以Collection的形式返回,以便其它应用程序引用,浏览上传文件信息。
原型:public Collection getCollection()
5、getEnumeration
作用:将所有上传文件对象以Enumeration(枚举)的形式返回,以便其它应用程序浏览上传文件信息。
原型:public Enumeration getEnumeration()
㈢ Request类
这个类的功能等同于JSP内置的对象request。只所以提供这个类,是因为对于文件上传表单,通过request对象无法获得表单项的值,必须通过jspSmartUpload组件提供的Request对象来获取。该类提供如下方法:
1、getParameter
作用:获取指定参数之值。当参数不存在时,返回值为null。
原型:public String getParameter(String name)。其中,name为参数的名字。
2、getParameterValues
作用:当一个参数可以有多个值时,用此方法来取其值。它返回的是一个字符串数组。当参数不存在时,返回值为null。
原型:public String[] getParameterValues(String name)。其中,name为参数的名字。
3、getParameterNames
作用:取得Request对象中所有参数的名字,用于遍历所有参数。它返回的是一个枚举型的对象。
原型:public Enumeration getParameterNames()
㈣ SmartUpload类这个类完成上传下载工作。
A.上传与下载共用的方法:
只有一个:initialize。
作用:执行上传下载的初始化工作,必须第一个执行。
原型:有多个,主要使用下面这个:
public final void initialize(javax.servlet.jsp.PageContext pageContext)
其中,pageContext为JSP页面内置对象(页面上下文)。
B.上传文件使用的方法:
1、upload
作用:上传文件数据。对于上传操作,第一步执行initialize方法,第二步就要执行这个方法。
原型:public void upload()
2、save
作用:将全部上传文件保存到指定目录下,并返回保存的文件个数。
原型:public int save(String destPathName)
和public int save(String destPathName,int option)
其中,destPathName为文件保存目录,option为保存选项,它有三个值,分别是SAVE_PHYSICAL,SAVE_VIRTUAL和SAVE_AUTO。(同File类的saveAs方法的选项之值类似)SAVE_PHYSICAL指示组件将文件保存到以操作系统根目录为文件根目录的目录下,SAVE_VIRTUAL指示组件将文件保存到以Web应用程序根目录为文件根目录的目录下,而SAVE_AUTO则表示由组件自动选择。
注:save(destPathName)作用等同于save(destPathName,SAVE_AUTO)。
3、getSize
作用:取上传文件数据的总长度
原型:public int getSize()
4、getFiles
作用:取全部上传文件,以Files对象形式返回,可以利用Files类的操作方法来获得上传文件的数目等信息。
原型:public Files getFiles()
5、getRequest
作用:取得Request对象,以便由此对象获得上传表单参数之值。
原型:public Request getRequest()
6、setAllowedFilesList
作用:设定允许上传带有指定扩展名的文件,当上传过程中有文件名不允许时,组件将抛出异常。
原型:public void setAllowedFilesList(String allowedFilesList)
其中,allowedFilesList为允许上传的文件扩展名列表,各个扩展名之间以逗号分隔。如果想允许上传那些没有扩展名的文件,可以用两个逗号表示。例如:setAllowedFilesList("doc,txt,,")将允许上传带doc和txt扩展名的文件以及没有扩展名的文件。
7、setDeniedFilesList
作用:用于限制上传那些带有指定扩展名的文件。若有文件扩展名被限制,则上传时组件将抛出异常。
原型:public void setDeniedFilesList(String deniedFilesList)
其中,deniedFilesList为禁止上传的文件扩展名列表,各个扩展名之间以逗号分隔。如果想禁止上传那些没有扩展名的文件,可以用两个逗号来表示。例如:setDeniedFilesList("exe,bat,,")将禁止上传带exe和bat扩展名的文件以及没有扩展名的文件。
8、setMaxFileSize
作用:设定每个文件允许上传的最大长度。
原型:public void setMaxFileSize(long maxFileSize)
其中,maxFileSize为为每个文件允许上传的最大长度,当文件超出此长度时,将不被上传。
9、setTotalMaxFileSize
作用:设定允许上传的文件的总长度,用于限制一次性上传的数据量大小。
原型:public void setTotalMaxFileSize(long totalMaxFileSize)
其中,totalMaxFileSize为允许上传的文件的总长度。
C.下载文件常用的方法
1、setContentDisposition
作用:将数据追加到MIME文件头的CONTENT-DISPOSITION域。jspSmartUpload组件会在返回下载的信息时自动填写MIME文件头的CONTENT-DISPOSITION域,如果用户需要添加额外信息,请用此方法。
原型:public void setContentDisposition(String contentDisposition)
其中,contentDisposition为要添加的数据。如果contentDisposition为null,则组件将自动添加"attachment;",以表明将下载的文件作为附件,结果是IE浏览器将会提示另存文件,而不是自动打开这个文件(IE浏览器一般根据下载的文件扩展名决定执行什么操作,扩展名为doc的将用word程序打开,扩展名为pdf的将用acrobat程序打开,等等)。
2、downloadFile
作用:下载文件。
原型:共有以下三个原型可用,第一个最常用,后两个用于特殊情况下的文件下载(如更改内容类型,更改另存的文件名)。
① public void downloadFile(String sourceFilePathName)
其中,sourceFilePathName为要下载的文件名(带目录的文件全名)
② public void downloadFile(String sourceFilePathName,String contentType)
其中,sourceFilePathName为要下载的文件名(带目录的文件全名),contentType为内容类型(MIME格式的文件类型信息,可被浏览器识别)。
③ public void downloadFile(String sourceFilePathName,String contentType,String destFileName)
其中,sourceFilePathName为要下载的文件名(带目录的文件全名),contentType为内容类型(MIME格式的文件类型信息,可被浏览器识别),destFileName为下载后默认的另存文件名。
posted @
2008-08-26 16:12 南山隐士 阅读(238) |
评论 (0) |
编辑 收藏
现在想要获得在特定时间或者指定时间执行相应功能
有两种做法
在applicationContext.xml中写入如下Bean
<bean id="repeatingTrigger"
class="org.springframework.scheduling.timer.ScheduledTimerTask">
<!--启动一秒后执行 -->
<property name="delay">
<value>1000</value>
</property>
<!--每隔一小时执行一次 -->
<property name="period">
<value>3600000</value>
</property>
<!--注入要监控的javaBean -->
<property name="timerTask">
<ref bean="task" />
</property>
<!--类型是否为fixedRate型,默认为fixedDelay-->
<property name="fixedRate">
<value>true</value>
</property>
</bean>
<bean id="scheduler"
class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="repeatingTrigger" />
</list>
</property>
</bean>
<bean id="task" class="com.css.wam.portlet.SampleTask">
<property name="workService">
<ref bean="workService" />
</property>
<property name="work">
<ref bean="work" />
</property>
</bean>
然后写SampleTask类,如下:
package com.css.wam.portlet;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.TimerTask;
import javax.servlet.ServletContext; 字串2
import org.apache.jetspeed.security.SecurityException; 字串9
import com.css.wam.service.WorkService; 字串1
@SuppressWarnings("unused")
class SampleTask extends TimerTask{ 字串2
private static final int C_SCHEDULE_HOUR = 23;//设置指定时间
private WorkService workService;
private List users;
private List teams;
private WorkPortlet work;
public void setWorkService(WorkService workService) {
this.workService = workService;
} 字串7
public void setWork(WorkPortlet work) {
this.work = work;
} 字串4
public SampleTask(){
}
@SuppressWarnings("unchecked")
public void run() {
Calendar cal = Calendar.getInstance();
try {
users = work.getUsers();
teams = new ArrayList();
for(Iterator it = users.iterator(); it.hasNext();)
{
String teamname = work.getGroupsByUser((String)it.next());
teams.add(teamname);
}
//查看当前时间与指定是否一致,一致则执行任务
if (C_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY) ) 字串6
workService.autoWorkOff(users, teams); 字串8
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
posted @
2008-06-25 17:14 南山隐士 阅读(1390) |
评论 (0) |
编辑 收藏
/*
* @(#)BeanXML.java 1.00 2005-10-7
*
* Copyright 2005 BeanSoft Studio. All rights reserved.
* PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package beansoft.xml;
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
/**
* BeanXML
*
* Chinese documents:
*
* @author BeanSoft
* @version 1.00 2005-10-7
*/
public class BeanXML {
/**
* 使用 java.beans.XMLEncoder 将 对象编码为 XML.
* @param bean 对象
* @return String - 编码后的 XML
*/
public static String encodeBean(Object bean) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLEncoder encoder = new XMLEncoder(out);
encoder.writeObject(bean);
encoder.close();
return out.toString();
}
/**
* 使用 java.beans.XMLDecoder 将 XML 解码为 对象.
* @param xml - 编码后的 XML
* @return Object 反编码后的对象
*/
public static Object decodeBean(String xml) {
try {
// FIXME 必须使用 GBK 解码才对, 否则出来的文字是乱码?
XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(xml.getBytes("GBK")));
return decoder.readObject();
} catch (UnsupportedEncodingException e) {
}
return null;
}
}
posted @
2008-06-25 16:12 南山隐士 阅读(1937) |
评论 (0) |
编辑 收藏
这需要导入java.io类
import java.io.*;
public class FileOperate {
public FileOperate() {
}
/**
* 新建目录
* @param folderPath String 如 c:/fqf
* @return boolean
*/
public void newFolder(String folderPath) {
try {
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
if (!myFilePath.exists()) {
myFilePath.mkdir();
}
}
catch (Exception e) {
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}
/**
* 新建文件
* @param filePathAndName String 文件路径及名称 如c:/fqf.txt
* @param fileContent String 文件内容
* @return boolean
*/
public void newFile(String filePathAndName, String fileContent) {
try {
String filePath = filePathAndName;
filePath = filePath.toString();
File myFilePath = new File(filePath);
if (!myFilePath.exists()) {
myFilePath.createNewFile();
}
FileWriter resultFile = new FileWriter(myFilePath);
PrintWriter myFile = new PrintWriter(resultFile);
String strContent = fileContent;
myFile.println(strContent);
resultFile.close();
}
catch (Exception e) {
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}
/**
* 删除文件
* @param filePathAndName String 文件路径及名称 如c:/fqf.txt
* @param fileContent String
* @return boolean
*/
public void delFile(String filePathAndName) {
try {
String filePath = filePathAndName;
filePath = filePath.toString();
java.io.File myDelFile = new java.io.File(filePath);
myDelFile.delete();
}
catch (Exception e) {
System.out.println("删除文件操作出错");
e.printStackTrace();
}
}
/**
* 删除文件夹
* @param filePathAndName String 文件夹路径及名称 如c:/fqf
* @param fileContent String
* @return boolean
*/
public void delFolder(String folderPath) {
try {
delAllFile(folderPath); //删除完里面所有内容
String filePath = folderPath;
filePath = filePath.toString();
java.io.File myFilePath = new java.io.File(filePath);
myFilePath.delete(); //删除空文件夹
}
catch (Exception e) {
System.out.println("删除文件夹操作出错");
e.printStackTrace();
}
}
/**
* 删除文件夹里面的所有文件
* @param path String 文件夹路径 如 c:/fqf
*/
public void delAllFile(String path) {
File file = new File(path);
if (!file.exists()) {
return;
}
if (!file.isDirectory()) {
return;
}
String[] tempList = file.list();
File temp = null;
for (int i = 0; i < tempList.length; i++) {
if (path.endsWith(File.separator)) {
temp = new File(path + tempList[i]);
}
else {
temp = new File(path + File.separator + tempList[i]);
}
if (temp.isFile()) {
temp.delete();
}
if (temp.isDirectory()) {
delAllFile(path+"/"+ tempList[i]);//先删除文件夹里面的文件
delFolder(path+"/"+ tempList[i]);//再删除空文件夹
}
}
}
/**
* 复制单个文件
* @param oldPath String 原文件路径 如:c:/fqf.txt
* @param newPath String 复制后路径 如:f:/fqf.txt
* @return boolean
*/
public void copyFile(String oldPath, String newPath) {
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) { //文件存在时
InputStream inStream = new FileInputStream(oldPath); //读入原文件
FileOutputStream fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ( (byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
}
}
catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
}
}
/**
* 复制整个文件夹内容
* @param oldPath String 原文件路径 如:c:/fqf
* @param newPath String 复制后路径 如:f:/fqf/ff
* @return boolean
*/
public void copyFolder(String oldPath, String newPath) {
try {
(new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
File a=new File(oldPath);
String[] file=a.list();
File temp=null;
for (int i = 0; i < file.length; i++) {
if(oldPath.endsWith(File.separator)){
temp=new File(oldPath+file[i]);
}
else{
temp=new File(oldPath+File.separator+file[i]);
}
if(temp.isFile()){
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(newPath + "/" +
(temp.getName()).toString());
byte[] b = new byte[1024 * 5];
int len;
while ( (len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if(temp.isDirectory()){//如果是子文件夹
copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
}
}
}
catch (Exception e) {
System.out.println("复制整个文件夹内容操作出错");
e.printStackTrace();
}
}
/**
* 移动文件到指定目录
* @param oldPath String 如:c:/fqf.txt
* @param newPath String 如:d:/fqf.txt
*/
public void moveFile(String oldPath, String newPath) {
copyFile(oldPath, newPath);
delFile(oldPath);
}
/**
* 移动文件到指定目录
* @param oldPath String 如:c:/fqf.txt
* @param newPath String 如:d:/fqf.txt
*/
public void moveFolder(String oldPath, String newPath) {
copyFolder(oldPath, newPath);
delFolder(oldPath);
}
}
java中删除目录事先要删除目录下的文件或子目录。用递归就可以实现。这是我第一个用到算法作的程序,哎看来没白学。
public void del(String filepath) throws IOException{
File f = new File(filepath);//定义文件路径
if(f.exists() && f.isDirectory()){//判断是文件还是目录
if(f.listFiles().length==0){//若目录下没有文件则直接删除
f.delete();
}else{//若有则把文件放进数组,并判断是否有下级目录
File delFile[]=f.listFiles();
int i =f.listFiles().length;
for(int j=0;j<i;j++){
if (delFile[j].isDirectory()){ del (delFile[j].getAbsolutePath());//递归调用del方法并取得子目录路径
}
delFile[j].delete();//删除文件
}
}
del(filepath);//递归调用
}
}
删除一个非空目录并不是简单地创建一个文件对象,然后再调用delete()就可以完成的。要在平台无关的方式下安全地删除一个非空目录,你还需要一个算法。该算法首先删除文件,然后再从目录树的底部由下至上地删除其中所有的目录。
只要简单地在目录中循环查找文件,再调用delete就可以清除目录中的所有文件:
static public void emptyDirectory(File directory) {
File[ ] entries = directory.listFiles( );
for(int i=0; i<entries.length; i++) {
entries[i].delete( );
}
}
这个简单的方法也可以用来删除整个目录结构。当在循环中遇到一个目录时它就递归调用deleteDirectory,而且它也会检查传入的参数是否是一个真正的目录。最后,它将删除作为参数传入的整个目录。
static public void deleteDirectory(File dir) throws IOException {
if( (dir == null) || !dir.isDirectory) {
throw new IllegalArgumentException(
"Argument "+dir+" is not a directory. "
);
}
File[ ] entries = dir.listFiles( );
int sz = entries.length;
for(int i=0; i<sz; i++) {
if(entries[i].isDirectory( )) {
deleteDirectory(entries[i]);
} else {
entries[i].delete( );
}
}
dir.delete();
}
在Java 1.1以及一些J2ME/PersonalJava的变种中没有File.listFiles方法。所以只能用File.list,它的返回值一个字符串数组,你要为每个字符串构造一个新的文件对象。
posted @
2008-06-25 08:25 南山隐士 阅读(1241) |
评论 (0) |
编辑 收藏
WebLogic Server包含了Timer Service功能,你可以指定某一时刻或某一时间间隔产生Timer事件,同时你可以使用委托代理的机制,为这个事件注册事件监听器,以实现Timer Service功能。
从WebLogic Server 7.0以后的版本,WebLogic Timer Service扩展自标准的JMX Timer Service,使其可以运行于WebLogic Server的执行线程中,并且享有WebLogic Server的安全上下文环境,也就是说,可以在代码中得到安全信息,如用户名等。下面结合一个实例演示其功能。
File:TimerServiceListener.java
package org.yekki.weblogic.timer;
import java.util.Date;
import java.util.Random;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.management.InstanceNotFoundException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.ecs.xml.XML;
import weblogic.management.timer.Timer;
public class TimerServiceListener
implements ServletContextListener, NotificationListener {
private long period;
private boolean debug;
private Timer timer;
private Integer notificationId;
private QueueConnectionFactory factory;
private QueueConnection connection;
private QueueSession session;
private QueueSender sender;
private Queue queue;
private Context ctx;
public void contextInitialized(ServletContextEvent event) {
initParams(event);
initJMS();
debug(">>> contextInitialized called.");
timer = new Timer();
timer.addNotificationListener(this, null, "Message Broker ");
Date timerTriggerAt = new Date((new Date()).getTime() + 5000L);
notificationId =
timer.addNotification(
"Timer Type",
"Timer Message",
this,
timerTriggerAt,
period);
timer.start();
debug(">>> timer started.");
printBrief();
}
public void initParams(ServletContextEvent event) {
ServletContext ctx = event.getServletContext();
try {
debug = Boolean.valueOf((String)ctx.getInitParameter("debug")).booleanValue();
}
catch (Exception e) {
debug = false;
e.printStackTrace();
}
try {
/*
second:1000L
minute:60000L
hour:3600000L
day:86400000L
week:604800000L
*/
period =
Long
.valueOf((String)ctx.getInitParameter("period"))
.longValue();
}
catch (Exception e) {
period = Timer.ONE_MINUTE;
e.printStackTrace();
}
debug(">>> initialized application parameters.");
}
private void initJMS() {
try {
ctx = new InitialContext();
factory =
(QueueConnectionFactory)ctx.lookup(
"javax.jms.QueueConnectionFactory");
queue = (Queue)ctx.lookup("queue");
connection = factory.createQueueConnection();
session =
connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
sender = session.createSender(queue);
connection.start();
debug(">>> initialized jms.");
}
catch (Exception e) {
e.printStackTrace();
}
}
public void sendMessage(String message) {
try {
TextMessage msg = session.createTextMessage();
msg.setText(message);
sender.send(msg);
debug(">>> ################################");
debug("Send a message on " + new Date());
debug(message);
debug(">>> ################################");
}
catch (JMSException e) {
e.printStackTrace();
}
}
public void contextDestroyed(ServletContextEvent event) {
debug(">>> contextDestroyed called.");
try {
timer.stop();
timer.removeNotification(notificationId);
debug(">>> timer stopped.");
}
catch (InstanceNotFoundException e) {
e.printStackTrace();
}
try {
if (session != null)
session.close();
if (connection != null)
connection.close();
debug(">>> closed jms connection and session.");
}
catch (JMSException e) {
e.printStackTrace();
}
}
private void printBrief() {
String d = "";
d = debug ? "ON" : "OFF";
print(">>> ################################");
print(">>> Author: Niu Xiuyuan");
print(">>> EMail: niuxiuyuan@bea.com.cn");
print(">>> Company: BEA Systems");
print("");
print(">>> Debug: " + d);
print(">>> Period: " + getPeriodInfo(period));
print(">>> ################################");
}
private void print(String str) {
System.out.println(str);
}
private String getPeriodInfo(long p) {
if (p == Timer.ONE_DAY)
return "One Day";
if (p == Timer.ONE_HOUR)
return "One Hour";
if (p == Timer.ONE_MINUTE)
return "One Minute";
if (p == Timer.ONE_SECOND)
return "One Second";
if (p == Timer.ONE_WEEK)
return "One Week";
return "Unsupported time period!! period=" + p;
}
public void handleNotification(Notification notif, Object handback) {
Random rnd = new Random();
sendMessage(genXML(rnd.nextInt(10)));
}
public String genXML(int id) {
String username = "guru";
String password = "niu986";
XML usernameXML = null;
XML idXML = null;
XML passwordXML = null;
XML userXML = null;
XML profileXML = new XML("profiles");
for (int i = 1; i <= id; i++) {
usernameXML = (new XML("user")).addElement(username);
idXML = (new XML("id")).addElement(Integer.toString(id));
passwordXML = (new XML("password")).addElement(password);
userXML =
(new XML("user"))
.addXMLAttribute("age", "27")
.addElement(idXML)
.addElement(usernameXML)
.addElement(passwordXML);
profileXML.addElement(userXML);
}
return profileXML.toString();
}
private void debug(String msg) {
if (debug) {
System.out.println(msg);
}
}
public static void main(String[] args) {
}
}
说明:为了方便演示,此类中包含了事件产生器代码与事件监听器代码。使用ServletContextListener接口来控制Timer的启动与停止。
File:web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>debug</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>period</param-name>
<param-value>60000</param-value>
</context-param>
<listener>
<listener-class>org.yekki.weblogic.timer.TimerServiceListener</listener-class>
</listener>
<login-config>
<auth-method></auth-method>
</login-config>
</web-app>
说明:我们将webapp的Lisener注册,并且指定事件产生的时间间隔
将此WebApp部署到WebLogic Server上,然后通过中端(例如:DOS窗口)查看实验结果。
附:本例中使用了Apache的ECS项目类库,您可以访问如下URL:
http://jakarta.apache.org/ecs/index.html
posted @
2008-06-23 10:16 南山隐士 阅读(745) |
评论 (0) |
编辑 收藏