今天继续佟老师的教育办公系统的旅程:
1. 员工录入的服务器端的简单验证:
1). 使用 struts 的 validator 框架
2). 验证规则同浏览器端的 jQuery 的 validator 验证.
3). 以 email 字段为例, 验证规则为非空, 且符合 email 格式
2. 员工录入的服务器端的复杂验证: 验证登录名是否在数据库中已经存在
1). 采取在 Action 的对应方法中使用 ActionMessages 的方法.
2). 可以采取 struts 的声明式异常吗?
3. 员工的录入操作
1). PY_NAME 需要根基 employee_name 字段进行动态生成, 需要额外的工具包: pinyin4j
2). 可以通过下边的方式为 Employee 对象的 position, dept 属性赋值
Position position = new Position(employee.getPositionid());
Department dept = new Department(employee.getDeptid());
employee.setPosition(position);
employee.setDept(dept);
4. 使用 displaytag 工具进行翻页:
1). 在 tomcat 的 webapps 目录下展示其实例.
2). 解决 displaytag 中文显示的问题: 修改其默认的配置文件: 把 displaytag 标签库中的 displaytag.properties 文件复制到 conf 目录下, 修改其对应信息即可
5. OpenSessionInView:
1). 为什么要使用 OpenSessionInView:
若 Hibernate 中某个类的某个引用属性(也包括集合属性)采取懒加载策略, 则可能会出现
org.hibernate.LazyInitializationException
在已经获取到该对象, 但没有对其懒加载属性进行初始化, 此时关闭 Session, 然后再来获取该属性时就会出现上述异常
同理若只是声明使用 spring 的声明式事务:
<aop:config>
<aop:pointcut expression_r="execution(* cn.itcast.ems.service.*.*(..))" id="emsTxPointcut"/>
<aop:advisor advice-ref="emsTxAdvice" pointcut-ref="emsTxPointcut"/>
</aop:config>
则此时在 * cn.itcast.ems.service.*.*(..) 方法执行完, spring 将关闭 Session, 那么再在页面上使用 ${emp.dept.departmentName} 获取
dept 属性信息时, 就会发生该异常
OpenSessionInView 可以解决这个问题
2). OpenSessionInViewFilter 调用流程:
request(请求) -> open session 并开始 transaction -> controller -> View(Jsp) -> 结束 transaction 并 close session.
因为关闭 Session 对象的时间被延迟到页面加载完之后(即: HttpRequest 对象生命周期结束), 所以此时在页面上就不会发生
org.hibernate.LazyInitializationException 异常
3). 配置, 在 web.xml 文件中加入如下配置:
4). 缺点: 如果流程中的某一步被阻塞, 而这期间的 connection 却一直被占用不被释放.
例如输出页面时, 一方面可能是页面内容大, response.write的时间长; 另一方面可能是网速慢, 服务器与用户间传输时间久.
当大量这样的情况出现时,就有连接池连接不足, 造成页面假死现象. 所以在内容多流量大的网站需慎用.
6. 通用翻页:
1). Page: 与具体 ORM 实现无关的分页参数及查询结果封装
2). PropertyFilter: 与具体 ORM 实现无关的属性过滤条件封装类, 主要记录页面中简单的搜索过滤条件:
①. 枚举的使用
②. 参见 note.ppt 第三页 和 PropertyFilterTest 的断点测试
3). HibernateDao: 扩展 SimpleHibernateDao, 功能包括分页查询, 按属性过滤条件列表:
①. 不带任何查询条件时, 需要使用的方法:
--countCriteriaResult**
--setPageParameter
--findPage(Page<T> page, Criterion...criterions)
②. 带查询条件时, 需要使用的方法:
--buildPropertyFilterCriterion(String propertyName, Object propertyValue, Class<?> propertyType, MatchType matchType)
--buildPropertyFilterCriterions(List<PropertyFilter> filters)
--find(List<PropertyFilter> filters)
--findPage(final Page<T> page, final List<PropertyFilter> filters)
7. 具体实现
1). 不带任何查询条件 , 非 Ajax 分页:
①. employee-list-1.do --> Action --> Service --> DAO
2). 带查询简单条件的翻页:
①. jQuery 的 thickbox 插件
②. /WEB-INF/pages/employees/employee-criteria.jsp 页面字段的 property 属性的设置
③. 在获取第一页的内容以后, 如何把查询条件带到第二页?
--把封装了查询条件的 List 放到 session 域中. 下一次只需从 Session 域中获取 --> 简单, 但会占用系统资源
--把查询条件放在隐藏域中 --> 性能好, 但实现较为复杂**, 该隐藏域需要放在 employee-list-1.jsp 页面中:
<input type="hidden" value="${param.filter_LIKES_loginname }" name="filter_LIKES_loginname">
④. 点击翻页连接时, 如何携带查询条件?
使用 jQuery 提供的 serialize() 方法获取查询字符串:
var url = this.href + "&" + $(":hidden").serialize();
window.location.href=url;
⑤. 点击 "增加(显示当前)查询条件" 时, 需要在 employee-criteria.jsp 页面能够显示出查询条件.
方案: 在点击 "增加(显示当前)查询条件" 链接时, 需要把隐藏域中的查询条件携带过去, 然后在 employee-criteria.jsp 页面中通过 el 得到查询条件
** 注意:
//以下代码为正解
$("#criteria").attr("href", $("#criteria").attr("href") + "&" + $(":hidden").serialize());
3). 带复杂属性的翻页:
①. 直接把 对 deptid 属性过滤加上会导致出现: org.hibernate.QueryException: could not resolve property: deptid of: cn.itcast.ems.domain.Employee
因为在 Employee 实体类中根本就没有 deptid 属性(并非指在 Employee 类中有该属性,而是要在映射文件中映射该属性).
②. 相对应的, 在 Employee 实体类中有 Department 类型的 dept 属性.
③. 解决: 在 EmployeeDao 中重写 Page<T> findPage(final Page<T> page, final List<PropertyFilter> filters) 方法, 以解决表单页面的 deptid 和 实体类的
dept 属性的对应问题
--> 增强 for 循环时, 不能 remove 其元素
--> 在循环时删除集合的元素, 会改变集合的 size 属性
今天学习的知识就是这些了,希望明天有更好的状态。