@实现一组功能的步骤
1,充分了解需求,包括所有的细节,需要知道要做一个什么样的功能
2,设计实体/表
• 正向工程:实体à映射文件à建表
• 反向工程:建表 à映射文件à实体
3,分析功能
• 分析到每个请求的粒度。
• 得到的结果是我们需要处理多少种请求,其中每种请求对应一个Action方法,如此就能写Action了。
4,实现功能:
• 1,创建Action,并定义出其中的方法。
• 2,实现Action方法,并创建出所用到的新的Service方法。
• 3,实现Service方法,并创建出所用到的新的Dao方法。
• 4,实现Dao方法。
• 5,创建并完成JSP页面。
5,测试、运行
@设计实体
1,有几个实体?
• 一般是一组增删改查对应一个实体。
2,实体之间有什么关系?
• 一般是页面引用了其他的实体时,就表示与这个实体有关联关系。
3,每个实体中都有什么属性?
• 1,主键。
• 2,关联关系属性。在类图中,关联关系是一条线,有两端,每一端对应一个表达此关联关系的属性。有几个端指向本类,本类中就有几个关联关系属性。
• 3,一般属性。分析所有有关的页面,找出表单中要填写的或是在显示页面中要显示的信息等。
• 4,特殊属性:为解决某问题而设计的属性。比如要显示年龄,但不会设计一个int age字段,而是一个Date birthday字段,年龄是在显示时实时计算出来的。
@hibernate实体映射
1,写注释
• 格式为:?属性,表达的是本对象与?的?关系。
• 例:“department属性,本对象与Department的多对一”
2,拷模板:
多对一 | <many-to-one name=“” class=“” column=“”/> |
一对多 (Set) | <set name=""> <key column=""></key> <one-to-many class=""/> </set> |
多对多 (Set) | <set name="" table=""> <key column=""></key> <many-to-many class="" column=""/> </set> |
3,填空:
• name属性:属性名(注释中的第1问号)
• class属性:关联的实体类型(注释中的第2个问号)
• column属性:
• <many-to-onecolumn="..">:一般可以写成属性名加Id后缀,如属性为department,则column值写成departmentId。
• 一对多中的<keycolumn="..">:从关联的对方(对方是多对一)映射中把column值拷贝过来。
• 多对多中的<key column=“..”>:一般可以写成本对象的名加Id后缀,如本对象名为User,则写为userId。
• 多对多中的<many-to-manycolumn=“..”>:一般可以写为关联对象的名称加Id后缀。
例子:
【实体类】
public class Role {
privateLong id;
privateString name;
privateString description;
privateSet<User> users = new HashSet<User>();
public class User {
privateLong id;
privateDepartment department;
privateSet<Role> roles = new HashSet<Role>();
privateString loginName; // 登录名
privateString password; // 密码
privateString name; // 真实姓名
privateString gender; // 性别
privateString phoneNumber; // 电话号码
privateString email; // 电子邮件
privateString description; // 说明
public class Department {
privateLong id;
privateSet<User> users = new HashSet<User>();
privateDepartment parent;
privateSet<Department> children = new HashSet<Department>();
privateString name;
privateString description;
【映射文件】
Role.hbm.xml
<hibernate-mappingpackage="cn.itcast.oa.domain">
<classname="Role" table="itcast_role">
<idname="id">
<generator class="native"/>
</id>
<propertyname="name"/>
<propertyname="description"/>
<!-- users属性,本类与User的多对多 -->
<setname="users" table="itcast_user_role">
<keycolumn="roleId"></key>
<many-to-manyclass="User" column="userId"></many-to-many>
</set>
</class>
</hibernate-mapping>
User.hbm.xml
<hibernate-mappingpackage="cn.itcast.oa.domain">
<classname="User" table="itcast_user">
<idname="id">
<generator class="native"/>
</id>
<propertyname="loginName"/>
<propertyname="password"/>
<propertyname="name"/>
<propertyname="gender" />
<propertyname="phoneNumber"/>
<propertyname="email"/>
<propertyname="description"/>
<!-- department属性,本类与Department的多对一 -->
<many-to-onename="department" class="Department" column="departmentId"></many-to-one>
<!-- roles属性,本类与Role的多对多 -->
<setname="roles" table="itcast_user_role">
<keycolumn="userId"></key>
<many-to-manyclass="Role" column="roleId"></many-to-many>
</set>
</class>
</hibernate-mapping>
Department.hbm.xml
<hibernate-mappingpackage="cn.itcast.oa.domain">
<classname="Department" table="itcast_department">
<idname="id">
<generatorclass="native" />
</id>
<propertyname="name" />
<propertyname="description" />
<!-- users属性,本类与User的一对多 -->
<setname="users">
<keycolumn="departmentId"></key>
<one-to-manyclass="User" />
</set>
<!-- parent属性,本类与Department(上级)的多对一 -->
<many-to-onename="parent" class="Department"column="parentId"></many-to-one>
<!--children属性,本类与Department(下级)的一对多 -->
<setname="children">
<keycolumn="parentId"></key>
<one-to-manyclass="Department" />
</set>
</class>
</hibernate-mapping>
每一个功能可能有好多请求(一般使用转发),功能与功能之间的切换就需要使用重定向。
@处理部门中的树状结构
说明:部门显示的两种方式:
①List页面直接显示部门的树状层级结构,可以使用树状列表样式
②列表页面只显示一层的(同级的)部门数据,默认显示最顶级的部门列表;点击部门名称,可以查看此部门相应的下级部门列表。
③删除部门时,同时删除此部门的所有下级部门【层级删除】。
下拉选择框
<s:select name="parentId"cssClass="SelectStyle"
list="#departmentList"listKey="id" listValue="name"
headerKey="" headerValue="==请选择部门=="/>
其中name="parentId"表示传输给服务器的key
list="#departmentList"表示从map中找到这个列表
listKey="id"listValue="name"分别表示从departmentList中的每个元素找id和name属性
headerKey="" headerValue="==请选择部门=="表示什么都不选的话key和value
指定了parentId后就能回显
级联删除
<!-- children属性,本类与Department(下级)的一对多 -->
<set name="children"cascade="delete">
<key column="parentId"></key>
<one-to-many class="Department"/>
</set>
@list方法中通过parentId确定层级
/** 列表 */
public String list() throws Exception {
List<Department> departmentList = null;
if(null == parentId){//说明是从部门管理连接过来的
departmentList = departmentService.findTopList();
}else{
departmentList = departmentService.findMyChildren(parentId);
Department parent = departmentService.getById(parentId);
ActionContext.getContext().put("parent", parent);
}
ActionContext.getContext().put("departmentList", departmentList);
return"list";
}
@添加和修改完成后,通过parentId加载原来层级的部门
<result name="toList"type="redirectAction">
department_list?parentId=${parentId}</result>
@删除超链接的action为
department_delete?id=%{id}&parentId=%{parent.id}
@<!-- 这个小细节就可以使新建页面事先选中当前部门的上级部门,于是默认添加的部门就是当前的兄弟部门 -->
<s:a action="department_addUI?parentId=%{parentId}">新建</s:a>
@<!-- 返回上一级部门,那么需要指定的parentId=parent.parent.id
Departmentparent = departmentService.getById(parentId);
ActionContext.getContext().put("parent", parent);
-->
<s:aaction="department_list?parentId=%{#parent.parent.id}">返回上一级</s:a>
懒加载问题:could not initialize proxy - no Session
懒加载异常的分析与解决
懒加载是由于session的关闭时间在访问关联对象属性之前。一般发生在页面中使用EL表达式或者OGNL表达式的时候访问与懒加载有关的属性,由于session已经关闭的时候所以异常。
解决办法就是关闭懒加载(适用于怎么都会加载的)延迟session的关闭时间,使用spring的OpenSessionInViewFilter
配置方式是:
在web.xml中添加一个filter
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
看url-pattern,这个过滤器知识对action请求进行过滤,而不对其他请求过滤,例如图片、其他没有用到session的请求,这样兼顾了效率和懒加载。这就是为什么struts2中要配置那个<constantname="struts.action.extension" value="action"/>,就是要明确说明struts2要处理的类型。