ERP项目分析:
Enterprise planning resource
客户关系、产品设计、生产管理、库存管理、采购管理、委外管理、资金控制、财务系统、人力资源、
协同办公、系统安全(日志、系统备份等)
mysql -u root -p<ondemand1.sql
http://localhost:8080/erp/home/login.jsp
http://localhost:8080/erp/main/index1.jsp
10个模块对应工程中的10个目录,主页面分为上中下三个帧,10个模块的主要区别就是中间那个帧
不一样,
body-unload事件可以把用户离开这个页面的行为捕捉到,保证整个页面始终是这个系统,中间
这个帧的更换由ajax来做。一旦页面变了,就会被body-unload捕捉到。
监听器来监听application和session。
如果一个用户已经登录,但是没有符合的权限,那么有一些页面也是不可以访问的!为了防止走后门
(直接从浏览器中输入地址),比如访问了一个路径,这个路径得先判断用户是否具备了访问这个路径
的权限。用了一个自定义标签来实现,名字是checkLogon
所有客户档案登记部分的页面都是以“register”开头的,其他部分的页面也是类似。这就可以通过
正则表达式来验证哪些页面可以被特定权限的用户所访问
比如拥有登记权限,那么以“register”开头的页面都可以访问,其他的模块也是类似……
Tree表,相当于左边的菜单栏的树状结构,如果菜单属于CRM模块,那么对应的表叫做CRM_tree,
通过一个表来生成树状信息!这个表甚至包括了每个叶节点的对应url,CRM_AllRight是用户
具备哪些权限,根据这个权限去CRM_tree表去找哪些树状列表的节点应该被当前用户显示出来。
对于树状菜单列表生成的问题,数据库设计需要注意什么问题呢?
首先得有itemId,还得有parentId,如果parentId是0的话那么就是一级菜单
对每个一级菜单进行for循环,然后通过select语句得到每一个一级菜单的直接子菜单,
然后再对二级菜单这么同样的for循环,里面还是用select这么处理。
一般都不这么做,性能上太差了……如果第一级的话,是001、002、003………………
第二级的话是第一级加上001、002、003………………也就是001001、001002、001003…………
同理,第三级的菜单号也类似来制定
然后select ………… order by id
一次就可以把这些都选出来了。而且是按照顺序出来的。然后根据这些id的length
来控制缩进,按照排列顺序直接就把这些菜单全显示出来了
插入id的时候,先找父id号,然后再找父id号对应的子id最大的号加上1就可以了,当然
这里稍微会麻烦一点。
=======================================================================
上午内容总结一下,还有安装时候出现的一些小问题:
conf里面的web.xml里面的默认servlet配置的listings设置为false的话,那么如果文件夹
里面没有欢迎页面的话,就不会将资源全部列出来,而是显示错误信息。
恩信ERP针对于各种不同的用户级别,看到的功能也不同,而且必须是公司的员工才能够使用这个系统,
也就是信息必须先录入这个系统(也就是档案录入,一般劳资的干事将这个信息录入)。档案录入员进入
恩信ERP系统的时候应该只能看到人力资源这一选项。然后在左边的人力资源档案管理中的人力资源档案
登记这里可以将信息存档。当然只是将档案存进来了而已,并不意味着这个被存入的员工就可以使用这个
系统了,还需要另外一个人在人力资源档案复核里面令其通过,这时员工才是真正进入了这个公司,但是
这时候由于没有权限,所以还是不能使用系统,还需要系统管理员分配权限。首先系统管理员在用户许可证
管理这里点击“许可证发放”,来授予权限,点击发放按钮,然后可以在下拉列表框里面选择各个模块以及
对应的权限,然后会生成许可证号码,这时这个员工就有了相应的权限了。
然后该员工可以注册,这时需要使用刚才生成的那个许可证号,这个号码每个人只有1个,表明每个人的
权限都是唯一的。然后就可以登录了。登录后就可以看到仅仅有给予的菜单而已。
==============================================================================
上面是整体说了一下业务流程,下面从编程的角度说一下吧:
从人力资源档案登记开始,这主要用到数据库里面的hr_file表,其中的LICENSE_TAG字段用于说明
该用户是否被颁发了许可证。
还有一个表hr_file_dig表,人力资源档案不可能一成不变的。变更前的信息就保存在这个表里面。就是
一个备份的作用,两个表的字段结构完全是一模一样。
人力资源档案变更的时候就要用到这个备份表,前一次变更的结果,将会保存在dig表中。
人力资源里面有个客户化的设置用来实现个性化的应用。
实际项目开发中需要注意一些问题,比如前端的javascript对合法性的验证,还要小心重复提交的
问题,比如利用后退回到前一个提交页面,然后再次提交,这是不能容许的,一般这种防止重复提交
是通过session实现,在表单里面有个字符串,session里面也放一个字符串,过滤器会比较这两个
字符串,提交的时候session迅速改变session里面的字符串,由于后退的页面不会进行刷新,所以
页面中的字符串不会改变,再次提交的时候就和session中的字符串对不上了。
复核通过就是通过更改登记表中的信息并且将其中的一个标志位设为1而实现的。
档案删除管理:其中有一个临时删除和永久删除的问题,可以通过在数据表中设置一个字段(标志位)
来实现,为0的时候是没有删除,1是临时删除,彻底删除的话就把记录彻底删了就成了。
许可证发放:涉及到security_license表:
用户许可证发放的主界面(列出各个主菜单和子菜单的界面)其实是和左边的树形菜单一个意思,也是
把它们都读出来,但是只不过树形菜单是通过javascript隐藏了子菜单而已。
设置好用户权限后,这些权限的信息是保存在design_allright表里面的。
许可证也是可以吊销的。许可证号码是采用1到9和A到Z的这些字符,每次随机生成五位就可以了。
通过时间值转换成mysql里面的md5就可以转换成为一个随机的串了,然后你再截取就成了,
具体可以参看javaWeb那本书里面的讲述。md5函数的特点就是哪怕输入的有1个比特的变化,那么
返回的值都是大相径庭的。
当然还有别的方法生成随机数,比如我将1到9这些数字和A到Z这些字符统一拼装成一个字符串,然后
每次使用随机数制造一个整数,这个整数是多少那么就从这个字符串取出第几位,就这样来循环生成
一个许可证号了(保证这个号里面只有1到9或A到Z这些字符)
//这里注意codes字符数组其实就是base64Code字符串转化成为字符数组的形式。
char codes[] = {'0','1',……'z'}
String base64Code="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/+";
byte[] buf = {78,79,23,45,66};//字节数组,里面有五个字节
base64Code.charAt((buf[0] >>> 2));
codes[(buf[0] >>> 2)]
(buf[0] >>> 2)是1个字节中的前6个比特的数据,由于2的6次方正好是64,这样(buf[0] >>> 2)必然
是0到63中的其中一个,那么既然base64Code中的字符个数正好是64的话,那么正好可以运用这个办法找
出随机数。
===================================================================================
在java中java.security里面MessageDigest类就是java程序里面的md5实现!
MessageDigest md = MessageDigest.getInstance("MD5");
然后md.digest(byte[] input)就可以返回md5函数返回的值了。
比如
String hex = "0123456789abcdef";
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Codes = md.digest("hello world itcast".getBytes());
StringBuffer sbf = new StringBuffer() ;
for(int i = 0 ; i < md5Codes.length ; i++)
{
sbf.appand(hex.charAt((md5Codes[i]>>>4)));
//注意md5Codes[i]>>>4是提取出高四位
sbf.append(hex.charAt((md5Codes[i]&0x0f))) ;
//这就是取出低四位了!
}
System.out.println(sbf.toString());
//这就输出了字节数组经过md5转换后,得到的新字符串了!
===============================================================================
目录树:
<style>
a {text-decoration=none;} //样式表定义超链接没有下划线
</style>
<script>
function showHide(id)
{
if(document.getElementById(id).style.display == "none")
{
document.getElementById(id).style.display = "block" ;
}
else
{
document.getElementById(id).style.display = "none"
}
}
</script>
<span><a href="javascript:showHide('parentmenu1')">parentmenu1</a></span>
<ul id="parentmenu1" style="display:none">
<li>submenu1</li>
<li>submenu2</li>
<li>submenu3</li>
</ul>
报警:有两种情况,一种是作为错误,一种是不作为错误;
前者的例子是比如就允许采购5个商品,你采购第六个的时候就出现错误,这就是作为错误。
后者的例子是比如你一个月没有登录系统的话,用户id会有被注销的危险,每次启动应用程序
的时候,用监听器来扫描数据库中超过1个月没有登录的用户,并将其列入黑名单中,
这就是属于不作为错误。
作为错误是可以即时检查出来的,错误出现就立即检出出来并给出提示,但是不作为错误只能
靠系统通过诸如定时器等手段来捕捉,不具备即时性。