SSH框架整合截图(二)
客户拜访管理
1 什么是客户拜访
(1)客户:与公司有业务往来的
(2)用户:可以使用系统的人
2 用户和客户关系
(1)用户和客户之间是拜访的关系
(2)用户 和 客户 是 多对多关系
** 一个用户可以拜访多个客户,一个客户可以被多个用户拜访
(3)多对多建表:
- 创建第三张表,使用外键维护关系
3 多对多配置
(1)缺陷:第三张表只有两个字段(两个id值)
4 把多对多拆分成两个一对多实现
(1)用户、客户、拜访
(2)用户 和 拜访是一对多
(3)客户和拜访是一对多
配置用户和客户关系
(传统多对多中 是不需要创建中间实体类的 而是在配置文件中 相互表示 然后自动建中间表 这里因为要在中间表中增加额外的属性值,所以不使用之前的方式,创建中间实体类的同时,增加一些其他属性(拜访地址,拜访内容等等),同时使该实体类和user和customer互相表示,即把多对多 拆分为两个一对多,客户和拜访 一对多 , 用户和拜访 一对多 配置时 类比这客户、联系人的关系 一对多 进行配置)
第一步 创建三个实体类
第二步 实体类之间互相表示
(1)用户和拜访一对多
- 在用户实体类表示所有拜访记录,使用set集合
- 在拜访实体类里面表示所属用户,使用对象
(2)客户和拜访一对多
- 在客户实体类表示所有拜访记录,使用set集合
- 在拜访实体类表示所属客户,使用对象
第三步 配置映射关系
(1)拜访实体类visit 基本属性配置
(2)用户和拜访一对多
- 在用户映射文件中表示所有拜访记录,使用set标签
- 在拜访映射文件中表示所属用户
(3)客户和拜访一对多
- 客户映射文件中表示所有拜访
- 在拜访映射文件中表示所属客户
最后把映射配置文件在核心配置文件中做引入
代码实践截图:
拜访实体类visit
user实体类
customer实体类
visit.hbm.xml
user.hbm.xml
customer.hbm.xml
在核心配置文件中引入映射文件之后,启动服务器 然后自动建表
总结:在多对多映射配置中,推荐使用此方式,因为中间表中一般都不只是两个外键组成的,还拥有自己的私有属性,传统的简单多对多配置只有两个外键,而这里将多对多拆分成了两个一对多来进行配置,配置的时候可以类比多对一(联系人和客户)的思路进行配置
visit和user(多对一) visit和customer(多对一)
----------------------------------------------------------------------------------------
添加页面:
<TABLE cellSpacing=0 cellPadding=0 width="98%" border=0>
<TBODY>
<TR>
<TD width=15 background=${pageContext.request.contextPath }/images/new_022.jpg><IMG
src="${pageContext.request.contextPath }/images/new_022.jpg" border=0></TD>
<TD vAlign=top width="100%" bgColor=#ffffff>
<TABLE cellSpacing=0 cellPadding=5 width="100%" border=0>
<TR>
<TD class=manageHead>当前位置:客户拜访管理 > 添加拜访</TD>
</TR>
<TR>
<TD height=2></TD>
</TR>
</TABLE>
<TABLE cellSpacing=0 cellPadding=5 border=0>
<tr>
<td>客户:</td>
<!-- 应该用下拉列表显示所有的客户 而不是让用户输入 所有就需要在到达该页面之前在域对象中保存所有客户的记录 用于在这里显示 -->
<td colspan="3">
<!--<input type="text" name="custId" style="WIDTH: 180px"/>
-->
<select name="customer.cid">
<c:forEach items="${listCustomer}" var="customer">
<option value="${customer.cid}">${customer.custName}</option>
</c:forEach>
</select>
</td>
</tr> <tr>
<td>用户:</td>
<!-- 应该用下拉列表显示所有的客户 而不是让用户输入 所有就需要在到达该页面之前在域对象中保存所有客户的记录 用于在这里显示 -->
<td colspan="3">
<!--<input type="text" name="custId" style="WIDTH: 180px"/>
-->
<select name="user.id">
<c:forEach items="${listUser}" var="user">
<option value="${user.id}">${user.name}</option>
</c:forEach>
</select>
</td>
</tr> <TR>
<td>拜访地址:</td>
<td>
<INPUT class=textbox id=sChannel2
style="WIDTH: 180px" maxLength=50 name="vaddress">
</td>
<td>拜访内容:</td>
<td>
<INPUT class=textbox id=sChannel2
style="WIDTH: 180px" maxLength=50 name="vcontent">
</td>
</TR> <tr>
<td rowspan=2>
<INPUT class=button id=sButton2 type=submit
value="保存 " name=sButton2>
</td>
</tr>
</TABLE>
运行界面:
在action中使用模型驱动
点击提交数据库中就保存了一条记录:
操作和一对多都一样,只是配置关系时 需要把多对多 拆分为两个一对多
------------------------------------------------------------------------------------
抽取BaseDao
内容介绍
1 代码review
2 抽取basedao代码重构方式
(1)在dao层,做操作最基本crud操作
(2)做crud操作时候,调用hibernate模板的方法都一样
(3)不同的是参数不同,
比如操作客户,传递客户对象,比如操作联系人,传递联系人对象
(4)抽取basedao,减少dao层大量重复的代码
3 使用反射+泛型实现抽取
(1)反射得到类的.class文件内容
- 得到类Class方式
-- Class.forName(...)
-- 类名.class
-- 对象.getClass() ;
this.getClass() ;
-- getClass方法是Object类的方法
(2)泛型术语
List<User> :
- <> :读成 typeof
- List<User> :整体部分读成 参数化类型
- <User> : <>中的User,读成 实际类型参数
具体实现
1 创建basedao接口,使用泛型方式
在接口里面定义操作的方法curd方法
2 创建BaseDao接口实现类
3 在真正功能的接口,继承basedao接口
(1)把实现crud操作的方法去掉了
4 让真正功能的实现类继承BaseDao实现类
(1)在真正的实现类,不需要继承hibernateDaoSupport,因为baseDaoImpl类继承了hibernateDaoSupport 所以不需要重复继承,所以customerdaoimpl对象中仍然需要注入sessionfactory对象
5 上面操作实现基本功能,有两个查询没有实现(需要得到当前操作的对象才能实现,比如findAll查询的时候,需要传递查询的实体类名,而这些操作需要在父类basedaoimpl的构造函数中进行 )
(1)根据id查询,返回对象
(2)查询所有
6 当customerdaoimpl实现类的对象创建的时候,父类的构造执行,即先执行basedaoimpl的构造方法,在这个方法中需要得到操作类的名称,结束之后才会调用custoemrdaoimpl类的构造方法
(1)在BaseDaoImpl的构造方法中得到传递对象的class
(2)得到BaseDaoImpl泛型里面Customer的class
7 具体实现
(1)得到运行类的class
(2)得到customerdaoimpl父类内容
(3)得到父类的参数化类型
(4)获取实际类型参数
(5)代码实现
private Class clazzType;
public BaseDaoImpl() {
//1 获取当前运行对象的class
//比如运行customerDao实现类,得到customerDao实现类class
Class clazz = this.getClass();
//2 获取运行类的父类的参数化类型BaseDaoImpl<Customer> 现在customerdaoimpl的父类是basedaoimpl 因为该类继承了basedaoimpl
Type type = clazz.getGenericSuperclass();
//3 转换成子接口ParameterizedType
ParameterizedType ptype = (ParameterizedType) type;
//4 获取实际类型参数
//比如 Map<key,value>
Type[] types = ptype.getActualTypeArguments();
//5 把Type变成class
Class clazzParameter = (Class) types[0];
this.clazzType = clazzParameter;
}
注意hql语句中,from后面是需要空格的
----------------------------------------------
代码实现,以customer为例
这里只有customerdaoimpl类继承了basedaoimpl 代码的执行顺序是:在创建custoemrdoaimpl对象之前,因为该类继承了basedaoimpl ,则,basedaoimpl就是customerdaoimpl的父类,那么在创建customerdaoimpl对象的时候,会先执行basedaoimpl
类的构造方法,然后才执行customerdaoimpl类的构造方法,可通过反射方式,在父类的构造方法中得到当前运行的类的名称
basedao接口:
package org.dao; import java.util.List; public interface BaseDao<T> {
//修改
public void update(T t);
//添加
public void add(T t);
//删除
public void delete(T t);
//查找所有
public List<T> findAll();
//根据id值 进行查找 一条记录
public T findOne(int id);
}
basedaoimpl:
package org.dao; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List; import org.model.Customer;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport; public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T>{
//这里只抽取最基本的方法 即增删改查
private Class classType=null;
public BaseDaoImpl() {
super();
//得到当前运行类的Class
16 Class clazz=this.getClass();
17 //得到运行类 的父类参数化类型 例如当前运行类是customer CustomerDaoImpl extends BaseDaoImpl<Customer>
18 //那么basedaoimpl是customerdaoimpl的父类, 最终得到的结果就是BaseDaoImpl<Customer>
19 Type type=clazz.getGenericSuperclass();
20 //强转 子接口
21 ParameterizedType ptype=(ParameterizedType) type;
22 //使用子接口中的方法 得到实际类型参数 即<>中的内容
23 Type[] types=ptype.getActualTypeArguments();
24 Class clazzParameter=(Class) types[0];
this.classType=clazzParameter;
} public void add(T t) {
this.getHibernateTemplate().save(t);
} public void delete(T t) {
this.getHibernateTemplate().delete(t);
} public void update(T t) {
this.getHibernateTemplate().update(t);
} public List<T> findAll() {//classType
//"from Customer"
return (List<T>)this.getHibernateTemplate().find("from "+classType.getSimpleName());
}
public T findOne(int id) {
//(Customer.class,id)
return (T) this.getHibernateTemplate().get(classType, id);
} }
customerdao:
package org.dao; import java.util.List; import org.model.Customer;
//接口之间也可以进行继承
public interface CustomerDao extends BaseDao<Customer>{//因为在basedao中已经存在了增删改查的方法,所以这里注释掉自己定义的方法
//T 真正实体类的名称 这里是customer
//void add(Customer customer); //List<Customer> findAll(); //Customer findOne(int id); //void delete(Customer c); //void update(Customer customer); int findCount(); List<Customer> findPage(int begin, int pageSize); List<Customer> findCondition(Customer customer); }
customerdaoimpl:
package org.dao; import java.util.List; import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.model.Customer;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
//该类继承HibernateDaoSupport类 不需要注入HibernateTemplate对象了 只用在配置文件中注入sessionfactory对象
//而做basedao抽取的时候 需要继承baseDao的实现类 因为该实现类继承了hibernateDaoSupport 所以这里就
//不需c复继承了 但是在spring配置文件中 CustomerDaoImpl中还是需要注入sessionfactory类的
//因为该类虽然没有直接继承hibernateDaoSupport 但是因为basedaoimpl继承了 本类又继承了 basedaoimpl
//所以这个类就继承了hibernateDaoSupport
//另外在继承basedaoimpl时 需要明确泛型的类型 把泛型替换为具体的对象类型
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao { // public CustomerDaoImpl() {
// super();
// System.out.println("customerdaoimpl......构造函数执行");
// }
/*
* 因为在basedaoimpl中已经做了抽取 把基本的增删改查操作都做了实现 而且继承了basedaoimpl 直接在service中调用即可
*
*
//向t_customer表中保存一条记录
public void add(Customer customer) {
//得到模板对象 使用方法进行数据的保存
this.getHibernateTemplate().save(customer);
}
//查询t_customer表中的所有记录
public List<Customer> findAll() {
// TODO Auto-generated method stub
return (List<Customer>) this.getHibernateTemplate().find("from Customer");
}
//根据id 查询对象
public Customer findOne(int id) {
// TODO Auto-generated method stub
return this.getHibernateTemplate().get(Customer.class,id);
}
//删除对象
public void delete(Customer c) {
// TODO Auto-generated method stub
this.getHibernateTemplate().delete(c);
}
//修改操作
public void update(Customer customer) {
// TODO Auto-generated method stub
this.getHibernateTemplate().update(customer);
}
*/
//查询总的记录数
public int findCount() {
// TODO Auto-generated method stub
//使用模板中的find方法来完成查询总记录数 查询出来的不是一个个的对象的集合
//而是一个数值 但是该方法反回的的是一个list集合 所以仍然需要使用list集合进行接收
List<Object>list=(List<Object>) this.getHibernateTemplate().find("select count(*) from Customer");
//从list中把值得到
if(list!=null&&list.size()!=0){
//变成int类型
Object obj=list.get(0);
//直接变是不行的 需要先变成Long型(long的包装类) 在转为int性
Long lobj=(Long) obj;
int count=lobj.intValue();
return count;
}
return 0;
}
//分页操作
public List<Customer> findPage(int begin, int pageSize) {
// TODO Auto-generated method stub
//创建离线DetachedCriteria对象 指明是对那个实体类进行操作
DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);
//第一个参数是离线对象 第二个 :起始位置 第三个 每页的大小(记录数)
List<Customer> list=(List<Customer>) this.getHibernateTemplate().findByCriteria(criteria,begin,pageSize);
return list;
}
//条件查询 输入的内容不为空
public List<Customer> findCondition(Customer customer) {
// TODO Auto-generated method stub
//第一种方式:
// SessionFactory sessionFactory=this.getHibernateTemplate().getSessionFactory();//得到sessionfactory对象
// Session session=sessionFactory.getCurrentSession();//得到session 这里的session对象和web阶段的HttpSession不是同一个概念
// Query query=session.createQuery("from Customer where custName like ?");
// query.setParameter(0,customer.getCustName());
// List<Customer> list=query.list(); //第二种方式: 单一条件查询的时候 这种比较简单 但是多条件查询的时候 使用第三中方式最简单
// List<Customer> list=(List<Customer>) this.getHibernateTemplate().find("from Customer where custName like ?","%"+customer.getCustName()+"%"); //第三种方式:
//创建离线对象,表示对那个实体类进行操作
DetachedCriteria criteria=DetachedCriteria.forClass(Customer.class);
//设置对实体类中的那个属性进行条件查询 如果对多个字段进行条件查询 那么只需要调用add方法即可
criteria.add(Restrictions.like("custName","%"+customer.getCustName()+"%"));
//调用模板中的方法 得到集合
List<Customer> list=(List<Customer>) this.getHibernateTemplate().findByCriteria(criteria);
return list;
} }
如果该实现类不注入sessionfactory,那么就会报错:
service中部分代码:因为继承了basedaoimpl 所以这里调用的方法 都是basedaoimpl中的方法
// 添加客户
public void add(Customer customer) {
// TODO Auto-generated method stub
customerDao.add(customer);
} // 客户列表
public List<Customer> findAll() {
// TODO Auto-generated method stub
return customerDao.findAll();
} // 根据id查询对象
public Customer findOne(int id) {
return customerDao.findOne(id);
} // 删除对象
public void delete(Customer c) {
// TODO Auto-generated method stub
customerDao.delete(c);
} // 修改操作
public void update(Customer customer) {
// TODO Auto-generated method stub
customerDao.update(customer);
}
这样统一的功能就由basedao进行实现,继承basedaoimpl类,就可以使用基本的增删改查操作,从而减少了大量的代码
--------------------------------
当customerdaoimpl和linkmandaoimpl两个实现类继承basedaoimpl的时候,服务器的启动截图:
说明创建对象之前会先调用父类中的构造方法,而在核心配置文件中是先引入的customer.xml文件,后引入的linkman.xml文件,所以加载配置文件的顺序就是先customer.xml后linkman.xml,所以在服务器启动的时候 先创建customer对象,后创建linkman对象,而创建这两个对象之前都会先调用其父类的构造方法。
-----------------------------------------------------------------------------------
多条件组合查询
第一种 写底层hibernate代码实现
第二种 使用hibernate模板里面find方法实现
- 写hql语句实现
//多条件组合查询
@SuppressWarnings("all")
public List<Customer> findMoreCondition(Customer customer) {
//使用hibernate模板里面find方法实现
//拼接hql语句
String hql = "from Customer where 1=1 ";
//创建list集合,如果值不为空,把值设置到list里面
List<Object> p = new ArrayList<Object>();
//判断条件值是否为空,如果不为空拼接hql语句
if(customer.getCustName()!=null && !"".equals(customer.getCustName())) {
//拼接hql
hql += " and custName=?";
//把值设置到list里面
p.add(customer.getCustName());
}
if(customer.getCustLevel()!=null && !"".equals(customer.getCustLevel())) {
hql += " and custLevel=?";
p.add(customer.getCustLevel());
}
if(customer.getCustSource()!=null && !"".equals(customer.getCustSource())) {
hql += " and custSource=?";
p.add(customer.getCustSource());
}
// System.out.println("hql: "+hql);
// System.out.println("list: "+p);
return (List<Customer>) this.getHibernateTemplate().find(hql, p.toArray());
}
第三种 使用离线对象和hibernate模板里面方法
第二种方式代码实现:
表单提交之后,把数据提交给action,因为action中使用了模型驱动,所以可以得到数据,如果没有输入任何东西,那么action中封装的模型对象中的数据就是为null,但是这不影响数据的检索,
action中直接调用service中的方法,service调用dao中的方法
下面是daoimpl中的方法:
//多条件查询
public List<Customer> moreCondition(Customer customer) {
List<Object> p=new ArrayList<Object>();
String hql="from Customer where 1=1";
//下面进行验证是否为空 并拼接hql字符串
if(customer.getCustName()!=null&&!"".equals(customer.getCustName())){
hql=hql+" and custName=?";
p.add(customer.getCustName());//如果值不为空 就把该值设置进list集合中
}
if(customer.getCustLevel()!=null&&!"".equals(customer.getCustLevel())){
hql += " and custLevel=?";
p.add(customer.getCustLevel());
}
if(customer.getCustSource()!=null&&!"".equals(customer.getCustSource())){
hql += " and custSource=?";
p.add(customer.getCustSource());
}
//第二个参数是一个可变参数(就是一种数组的形式) 需要把list集合变为数组
return (List<Customer>) this.getHibernateTemplate().find(hql,p.toArray());
}
在这方法中,我们采用的是字符串拼接的方式来构造hql语句,因为用户可能什么也没用输入,所以就需要判断是否为空,如果为空,那么if语句就都没有执行,所以hql语句就变为:
String hql="from Customer where 1=1";
当然是查询所有了
所以通过字符串拼接的方式,就能够完成多条件的查询操作 第三种方式代码实现:
daoimpl代码:
//多条件查询
public List<Customer> moreCondition(Customer customer) {
//第二种方式:使用离线对象
DetachedCriteria c=DetachedCriteria.forClass(Customer.class);//DetachedCriteria离线查询
//仍然需要验证是否为空 如果不为空 就像离线对象中插入限制条件 并且设置值
if(customer.getCustName()!=null&&!"".equals(customer.getCustName())){
c.add(Restrictions.eq("custName",customer.getCustName()));
}
if(customer.getCustLevel()!=null&&!"".equals(customer.getCustLevel())){
c.add(Restrictions.eq("custLevel",customer.getCustLevel()));
}
if(customer.getCustSource()!=null&&!"".equals(customer.getCustSource())){
c.add(Restrictions.eq("custSource",customer.getCustSource()));
}
//调用方法 执行查询
return (List<Customer>) this.getHibernateTemplate().findByCriteria(c);
}
DetachedCriteria--离线查询
Restrictions--条件限制
SSH框架整合截图(二)的更多相关文章
- SSH框架整合截图总结(一)
分页相关属性 --------------------------------------------------------------- 分页思路表单提交(只需传递当前页的值) ->acti ...
- SSH框架整合截图总结(三)
联系人信息查询1 点击 联系人信息查询 超链接时候,到查询页面 (1)在查询页面中,选择客户,根据客户进行查询 下拉表框显示所有客户 可以根据所属的客户进行联系人查询 2 在查询页面中,输入值,提 ...
- SSH框架整合
SSH框架整合 一.原理图 action:(struts2) 1.获取表单的数据 2.表单的验证,例如非空验证,email验证等 3.调用service,并把数据传递给service Service: ...
- dwr与ssh框架整合教程
(1)dwr与ssh框架整合教程dwr框架介绍. DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开 发人员开发包含AJ ...
- ssh框架整合之登录以及增删改查
1.首先阐述一下我用得开发工具,myeclipse2017+oracle,所以我的基本配置步骤可能不一样,下面我用几张图来详解我的开发步骤. ---1先配置structs (Target 选择apac ...
- Spring+Hibernate+Struts(SSH)框架整合
SSH框架整合 前言:有人说,现在还是流行主流框架,SSM都出来很久了,更不要说SSH.我不以为然.现在许多公司所用的老项目还是ssh,如果改成流行框架,需要成本.比如金融IT这一块,数据库dao层还 ...
- MVC+Spring.NET+NHibernate .NET SSH框架整合 C# 委托异步 和 async /await 两种实现的异步 如何消除点击按钮时周围出现的白线? Linq中 AsQueryable(), AsEnumerable()和ToList()的区别和用法
MVC+Spring.NET+NHibernate .NET SSH框架整合 在JAVA中,SSH框架可谓是无人不晓,就和.NET中的MVC框架一样普及.作为一个初学者,可以感受到.NET出了MV ...
- SSH框架整合过程总结
---------------------siwuxie095 SSH 框架整合过程总结 (一)导入相关 jar 包(共 ...
- J2EE进阶(十)SSH框架整合常见问题汇总(一)
SSH框架整合常见问题汇总(一) 前言 以下所列问题具有针对性,但是遇到同类型问题时均可按照此思路进行解决. HTTP Status 404 - No result defined for actio ...
随机推荐
- Embedded Android 协同翻译
假设你有一定的Android的基础和英语基础. 有愿意贡献开源社区的心. 假设你对下面文件夹感兴趣, 欢迎增加我们协同翻译<Embedded Android> 此次协同翻译.将使用gith ...
- 创建MAVEN项目报错
创建MAVEN项目pom.xml报错 Failure to transfer org.apache.maven:maven-archiver:jar:2.4.2 from http://repo.ma ...
- luogu4011 孤岛营救问题 分层图
关键词:分层图 状态压缩 最短路径 分层图:现在要求从起点到终点的最优路线,但受到手里拿着哪些钥匙的影响,最优路线不单纯了.因此,决定一个节点.一条边的存在的数中应当增加一个手中拿有钥匙的状态.这样就 ...
- 【撸码caffe 一】syncedmen.hpp
SyncedMemory类主要负责在主机(CPU)和设备(GPU)之间管理内存分配和数据同步工作,封装了CPU和GPU之间的数据交互操作. 补充一点GPU的相关知识: 对CUDA架构而言,主机端的内存 ...
- UVA-12578 10:6:2 计算几何 模拟
题面 题意:给你一块长方形,告诉你长:宽=10:6 里面有一个圆,长:半径=5:1,给你长方形的长,求圆的面积和剩余部分的面积 题解:直接模拟输出就好 #include<bits/stdc++. ...
- Windows下Python + AutoCAD 多义线绘图小结
简介 在windows下台下, 使用comtypes库, 通过ActiveX操作autocad, 从而读取AutoCAD数据 comtypes.client AutoCAD ActiveX GetAc ...
- 大数据学习之路------借助HDP SANDBOX开始学习
一开始... 一开始知道大数据这个概念的时候,只是感觉很高大上,引起了我的兴趣.当时也不知道,这个东西是做什么的,有什么用,当然现在看来也是很模糊的样子,但是的确比一开始强了不少. 所以学习的过程可能 ...
- C#服务控件UpdatePanel的局部刷新与属性AutoPostBack回传
C#服务控件许多都有AutoPostBack这一属性(AutoPostBack意思是自动回传,也就是说此控件值更改后是否和服务器进行交互),如下代码所示: protected void Textbox ...
- 一次显式GC导致的High CPU问题处理过程
项目现场反馈系统出现性能问题,具体表现为:所有的客户端响应极其卡顿. 第一反应推测,难道是DB层面出现阻塞?检查v$session会话状态及等待类型未见异常,应该可以排除DB层面原因导致的可能. 继续 ...
- mybatis学习笔记之基础框架(2)
mybatis学习笔记之基础框架(2) mybatis是一个持久层的框架,是apache下的顶级项目. mybatis让程序将主要精力放在sql上,通过mybatis提供的映射方式,自由灵活生成满足s ...