首页 > 代码库 > SSH的简单入门体验(Struts2.1+Spring3.1+Hibernate4.1)- 查询系统(下)
SSH的简单入门体验(Struts2.1+Spring3.1+Hibernate4.1)- 查询系统(下)
我们继续吧,SSH最大的优点就是实现的系统的松耦合,能够将后台和前台有机的分离开来。
一、目录结构
一个好的程序要有一个好的开始。我们先来看看整个目录结构吧
主要的是三层架构概念,或者说是mvc的概念。
二、Hibernate实体类
- 首先大家要懂得Hibernate运行的机制,简单的说就是你建一个类,然后将这个类映射到Hibernate中作为数据库的一张表,通过对这个类的操作来进行数据库的增删改查。具体的概念可以上网度查找资料或者通过书籍来学习。由于我也没有系统的学过,这里就不便详细的阐述了。
- 那么我们先建立一个实体类放在cpacm.pojo包下,名为Archive,表示文书档案类。具体代码如下:
package cpacm.pojo;public class Archive { private int aid; private String title; private String year;//年度 private String dcNumber;//文号 private int classid;//分类号 private String fileNum;//案卷号 private String location;//所在地 private String level;//密级 private String outDate;//保管期限 private String partNum;//件号 private String date1;//录入日期开始 private String date2;//录入日期结束 private int isBorrow;//是否出借 //Hibernate要求必须有一个空的构造函数 public Archive() { } //自定义的一个构造函数 public Archive(int aid, String title, String year, String dcNumber, int classid, String fileNum, String location, String level, String outDate, String partNum, String date1, String date2, int isBorrow) { super(); this.aid = aid; this.title = title; this.year = year; this.dcNumber = dcNumber; this.classid = classid; this.fileNum = fileNum; this.location = location; this.level = level; this.outDate = outDate; this.partNum = partNum; this.date1 = date1; this.date2 = date2; this.isBorrow = isBorrow; } //下面都是属性的get,set方法 public int getAid() { return aid; } public void setAid(int aid) { this.aid = aid; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getYear() { return year; } public void setYear(String year) { this.year = year; } public String getDcNumber() { return dcNumber; } public void setDcNumber(String dcNumber) { this.dcNumber = dcNumber; } public int getClassid() { return classid; } public void setClassid(int classid) { this.classid = classid; } public String getFileNum() { return fileNum; } public void setFileNum(String fileNum) { this.fileNum = fileNum; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } public String getLevel() { return level; } public void setLevel(String level) { this.level = level; } public String getOutDate() { return outDate; } public void setOutDate(String outDate) { this.outDate = outDate; } public String getPartNum() { return partNum; } public void setPartNum(String partNum) { this.partNum = partNum; } public String getDate1() { return date1; } public void setDate1(String date1) { this.date1 = date1; } public String getDate2() { return date2; } public void setDate2(String date2) { this.date2 = date2; } public int getIsBorrow() { return isBorrow; } public void setIsBorrow(int isBorrow) { this.isBorrow = isBorrow; } }
- 接下来我们要把这个类的和hibernate的数据库绑定,有两种方法:(1)xml配置文件;(2)注解。我们这里用配置文件来进行绑定,注解的话会比较方便,大家有兴趣的话可以自己尝试用注解来映射。
那么我们建立一个叫做Archive.hbm.xml的配置文件(注意文件名要与实体类Archive对应,方便我们查找),跟实体类Archive.java放在一起。配置代码如下
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><!-- name是表示你要映射类的位置。table表示你要在数据库生成的表名 --> <class name="cpacm.pojo.Archive" table="Archive"> <id name="aid"> <!-- 实体类中属性名 下同--> <column name="aid" /> <!-- 表中的列名 下同--> <generator class="native"></generator><!-- 自增长id --> </id> <property name="title" > <column name="title" length="50" /> </property> <property name="year" > <column name="year" length="10" /> </property> <property name="classid"> <column name="classid" not-null="true" /> </property> <property name="dcNumber" > <column name="dcNumber" length="20" /> </property> <property name="fileNum" > <column name="fileNum" length="20" /> </property> <property name="location" > <column name="location" length="20" /> </property> <property name="level" > <column name="level" length="20" /> </property> <property name="outDate" > <column name="outDate" length="20" /> </property> <property name="partNum"> <column name="partNum" length="20" /> </property> <property name="date1"> <column name="date1" /> </property> <property name="date2"> <column name="date2" /> </property> <property name="isBorrow" > <column name="isBorrow"/> </property> </class></hibernate-mapping>
- 最后到spring的配置文件applicationContext.xml中,告知spring有实体类要与Hibernate绑定
<!-- 配置实体Hibernate的描述文件 --> <property name="mappingResources"> <list> <!-- 实体类列表 --> <value>cpacm/pojo/Archive.hbm.xml</value> </list> </property>
放在bean id="sessionFactory"的内部中。具体可以看看上一篇中的applicationContext.xml代码
这样实体类的映射就完成了,接下来我们来看看怎么在SSH中用Hibernate操作数据库。
三、Hibernate数据层DAO
- Dao层以及后面的Service层我们要创建大量的接口来进行操作,虽然繁琐,但会充分体现整个系统设计的优点(像可移植性,可扩充性等)
- 首先我们要建立一个共用的Dao类和接口在cpacm.dao包中
IDao接口package cpacm.dao;import java.io.Serializable;import java.util.List;public interface IDao<T, ID extends Serializable> { public void save(T transientInstance) throws Exception; public void delete(T persistentInstance) throws Exception; public void update(T instance) throws Exception; public int updateByQuery(String hql); public T findById(ID id); public List<T> findAll(); public List<T> queryForPage(String hql, int offset, int length); public List<T> findByQuery(String queryString);}
里面包含了各个数据库的操作
Dao类package cpacm.dao;import java.io.Serializable;import java.lang.reflect.ParameterizedType;import java.util.List;import org.hibernate.Criteria;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.criterion.Criterion;public abstract class Dao<T,ID extends Serializable> implements IDao<T, ID>{ private SessionFactory sessionFactory;//加载数据库连接(使用spring实现加载) private Class<T> persistentClass; //sessionFactory的get和set方法。 public SessionFactory getSessionFactory() { return sessionFactory; } public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } //用构造方法处理Class<T>以下为固定模式 @SuppressWarnings("unchecked") public Dao() { this.persistentClass = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } public Class<T> getPersistentClass() { return persistentClass; } //对表的操作(增删改查) //保存 public void save(T transientInstance) throws Exception { try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); session.save(transientInstance); session.getTransaction().commit(); } catch (RuntimeException e) { throw e; } } //删除 public void delete(T persistentInstance) throws Exception { try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); session.delete(persistentInstance); session.getTransaction().commit(); } catch (RuntimeException e) { throw e; } } //更新 public void update(T instance) throws Exception { try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); session.saveOrUpdate(instance); session.getTransaction().commit(); } catch (RuntimeException e) { // TODO: handle exception throw e; } } //根据传进来的HQL语句更新,返回受影响行数 public int updateByQuery(String hql) { int k=0; try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); k=session.createQuery(hql).executeUpdate(); session.getTransaction().commit(); } catch (RuntimeException e) { // TODO: handle exception throw e; } return k; } //根据传进来的ID进行查询 public T findById(ID id) { try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); @SuppressWarnings("unchecked") T instance = (T) session.get(getPersistentClass(), id); session.getTransaction().commit(); return instance; } catch (RuntimeException e) { // TODO: handle exception throw e; } } //根据传进来的hql查询 @SuppressWarnings("unchecked") public List<T> findByQuery(String hql) { try { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); List<T> q = session.createQuery(hql).list(); session.getTransaction().commit(); return q; /*return sessionFactory.getCurrentSession().createQuery(hql).list();*/ } catch (RuntimeException e) { // TODO: handle exception throw e; } } //查找所有表里的所有内容 public List<T> findAll() { try { return findByCriteria();//调用下面的findByCriteria方法 } catch (RuntimeException e) { // TODO: handle exception throw e; } } //查找表里的所有内容并返回 @SuppressWarnings("unchecked") protected List<T> findByCriteria(Criterion... criterion) { Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); Criteria crit = session.createCriteria( getPersistentClass()); session.getTransaction().commit(); for (Criterion c : criterion) { crit.add(c); } return crit.list(); } //jQuery Easyui Datagrid需要的方法,根据传进来的hql,当前页数,页面长度返回数据列 public List<T> queryForPage(String hql, int offset, int length) { try{ Session session= getSessionFactory().getCurrentSession(); session.getTransaction().begin(); @SuppressWarnings("unchecked") List<T> results=session.createQuery(hql) .setFirstResult(offset) .setMaxResults(length) .list(); session.getTransaction().commit(); return results; }catch (RuntimeException re) { throw re; } }}
- 接下来继续在cpacm.dao中针对实体类建立dao类和接口
IArchiveDaopackage cpacm.dao;import cpacm.pojo.Archive;public interface IArchiveDao extends IDao<Archive,Integer>{}
很简单,继承公用Dao接口就行了
ArchiveDaopackage cpacm.dao;import cpacm.pojo.Archive;public class ArchiveDao extends Dao<Archive, Integer> implements IArchiveDao { }
一样简单,继承公用Dao类和IArchive接口
如此一来,我们就可以扩展ArchiveDao数据操作的功能。
四、逻辑设计Service层
设计方式跟Dao层类似,同样也是设计成接口模式。且更重要的一点是接口是继承Dao层的实体接口,这样保证了行为的一致性,如下
IArchiveService
package cpacm.service;import cpacm.dao.IArchiveDao;public interface IArchiveService extends IArchiveDao {}
ArchiveService
package cpacm.service;import java.util.List;import cpacm.dao.ArchiveDao;import cpacm.pojo.Archive;public class ArchiveService implements IArchiveService { private ArchiveDao archiveDao;//加载数据库操作类(使用spring实现加载) @Override public void save(Archive transientInstance) throws Exception { // TODO Auto-generated method stub archiveDao.save(transientInstance); } @Override public void delete(Archive persistentInstance) throws Exception { // TODO Auto-generated method stub archiveDao.delete(persistentInstance); } @Override public void update(Archive instance) throws Exception { // TODO Auto-generated method stub archiveDao.update(instance); } @Override public int updateByQuery(String hql) { // TODO Auto-generated method stub return archiveDao.updateByQuery(hql); } @Override public Archive findById(Integer id) { // TODO Auto-generated method stub return archiveDao.findById(id); } @Override public List<Archive> findAll() { // TODO Auto-generated method stub return archiveDao.findAll(); } @Override public List<Archive> queryForPage(String hql, int offset, int length) { // TODO Auto-generated method stub return archiveDao.queryForPage(hql, offset, length); } @Override public List<Archive> findByQuery(String queryString) { // TODO Auto-generated method stub return archiveDao.findByQuery(queryString); } public ArchiveDao getArchiveDao() { return archiveDao; } public void setArchiveDao(ArchiveDao archiveDao) { this.archiveDao = archiveDao; } }
五、Struts控制层Action
这一块是我们与前台交互最重要的部分,通过设定Action的行为来控制后台。
- ArchiveAction类
package cpacm.action;import java.util.Iterator;import java.util.List;import com.opensymphony.xwork2.ActionSupport;import cpacm.pojo.Archive;import cpacm.service.ArchiveService;import cpacm.service.BaseService;public class ArchiveAction extends ActionSupport { /** * */ private static final long serialVersionUID = 7966166028096000810L; private Archive acv = new Archive(); private BaseService<Archive> baseService; private ArchiveService archiveService;//加载逻辑设计类(使用spring实现加载) private List<Archive> Archives; private static String lastQueryString; private int tag; public String Query() { String queryString; queryString = "select a from Archive as a "; queryString += "where "; queryString += "a.classid like ‘%" + acv.getClassid() + "%‘ "; queryString += "and "; queryString += "a.date1 like ‘%" + acv.getDate1() + "%‘ "; queryString+="and "; queryString+="date2 like ‘%"+acv.getDate2()+"%‘ "; queryString+="and "; queryString+="dcNumber like ‘%"+acv.getDcNumber()+"%‘ "; queryString+="and "; queryString+="fileNum like ‘%"+acv.getFileNum()+"%‘ "; queryString+="and "; queryString+="level like ‘%"+acv.getLevel()+"%‘ "; queryString+="and "; queryString+="location like ‘%"+acv.getLocation()+"%‘ "; queryString+="and "; queryString+="outDate like ‘%"+acv.getOutDate()+"%‘ "; queryString+="and "; queryString+="partNum like ‘%"+acv.getPartNum()+"%‘ "; queryString+="and "; queryString+="title like ‘%"+acv.getTitle()+"%‘ "; queryString+="and "; queryString+="year like ‘%"+acv.getYear()+"%‘ "; lastQueryString = queryString; System.out.println("lastQueryString"+lastQueryString); System.out.println("queryString"+queryString); Archives = archiveService.findByQuery(queryString); return "Query"; } public String LastQuery(){ Archives = archiveService.findByQuery(lastQueryString); return "Query"; } public String toUpdate(){ acv = archiveService.findById(acv.getAid()); return "toUpdate"; } public String Update(){ try { archiveService.update(acv); LastQuery(); return "success"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "fail"; } } public String Delete(){ try { archiveService.delete(acv); LastQuery(); return "success"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "fail"; } } public String Add(){ try { archiveService.save(acv); return "success"; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return "fail"; } } public String QueryByclassID(){ String queryString; queryString = "select a from Archive as a "; queryString += "where "; queryString += "a.classid = ‘" + acv.getClassid() + "‘"; System.out.println("queryString"+queryString); lastQueryString = queryString; Archives = archiveService.findByQuery(queryString); return "success"; } public Archive getAcv() { return acv; } public void setAcv(Archive acv) { this.acv = acv; } public BaseService<Archive> getBaseService() { return baseService; } public void setBaseService(BaseService<Archive> baseService) { this.baseService = baseService; } public List<Archive> getArchives() { return Archives; } public void setArchives(List<Archive> archives) { Archives = archives; } public ArchiveService getArchiveService() { return archiveService; } public void setArchiveService(ArchiveService archiveSerive) { this.archiveService = archiveSerive; } public int getTag() { return tag; } public void setTag(int tag) { this.tag = tag; }}
在struts.xml定义的Action行为都在这里实现,然后返回一个字段(像success,fail等的字符串来决定执行Action后要跳转的页面。
具体代码请看上一篇的Struts.xml代码。 - 像在下面这段配置代码中
<action name="query" class="ArchiveAction" method="Query"> <result name="Query">/frame/ArcDataGrid.jsp</result></action>
前台访问query,然后会转入ArchiveAction(这里是spring的id,里面存放着文件的路径)所在的路径,执行Query()方法。
如果返回了一个"Query"的字符串,就会跳到/frame/ArcDataGrid.jsp页面。
这样就实现了控制器的效果。
六、Spring反转控制注入bean
不知道大家刚才有没有注意到刚才的类中有几个对象是没有实例化的,这里就是使用了Spring的反转控制。
像这里
private ArchiveDao archiveDao;//加载数据库操作类(使用spring实现加载)
(重要的是你要为这些类设置set,get方法)
它是通过Spring的配置文件实现的
以上后台的部分就算是结束了,那么我们通过前台来实现吧。
七、JSP前台页面
前台界面比较多,我这里就摘录比较重要的代码。首先是网页的预览图
- 首页
主要代码:<li data-options="state:‘opened‘"> <span><a href="frame/ArcQuery.jsp " target= "myiframe">文书档案类</a></span> <ul> <li> <span><a href="queryByclassId?acv.classid=10" target= "myiframe">综合类(A)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=20" target= "myiframe">计划财务类(B)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=30" target= "myiframe">地籍管理类(C)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=40" target= "myiframe">国土资源利用规划类(D)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=50" target= "myiframe">建设用地类(E)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=60" target= "myiframe">国土资源监察类(F)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=70" target= "myiframe">国土资源宣教、科技、信息类(G)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=80" target= "myiframe">电子、声像材料类(H)</a></span> </li> <li> <span><a href="queryByclassId?acv.classid=90" target= "myiframe">地质、矿产管理类(I)</a></span> </li> <li> <span><a href="frame/ArcAddData.jsp" target= "myiframe">添加数据</a></span> </li> </ul> </li>
<form id="ff" method="post" action="query"> <table cellpadding="6"> <tr> <td>题名:</td> <td><input class="easyui-textbox" type="text" name="acv.title" data-options="required:false" style="width:605px;"> </input></td> </tr> <tr> <td>年度:</td> <td><select class="easyui-combobox" name="acv.year" style="width:100px"> <option value="" selected="selected">不限年份</option> <option value="2011">2011</option> <option value="2012">2012</option> <option value="2013">2013</option> <option value="2014">2014</option> </select></td> <td>所在地:</td> <td><select class="easyui-combobox" name="acv.location" style="width:100px"> <option value="" selected="selected">不限地区</option> <option value="浙江省">浙江省</option> <option value="上海市">上海市</option> <option value="海南省">海南省</option> <option value="北京市">北京市</option> </select></td> </tr> <tr> <td>文号:</td> <td><input class="easyui-textbox" type="text" name="acv.dcNumber" style="width:270px;"> </input></td> <td>密级:</td> <td><input class="easyui-textbox" type="text" name="acv.level" style="width:270px;"> </input></td> </tr> <tr> <td>分类号:</td> <td><select class="easyui-combobox" name="acv.classid" style="width:230px"> <option value="0" selected="selected">不限分类</option> <option value="10">综合类(A)</option> <option value="20">计划财务类(B)</option> <option value="30">地籍管理类(C)</option> <option value="40">国土资源利用规划类(D)</option> <option value="50">建设用地类(E)</option> <option value="60">国土资源监察类(F)</option> <option value="70">国土资源宣教、科技、信息类(G)</option> <option value="80">电子、声像材料类(H)</option> <option value="90">地质、矿产管理类(I) </option> </select></td> <td>保管期限:</td> <td><select class="easyui-combobox" name="acv.outDate" style="width:100px"> <option value="" selected="selected">不限</option> <option value="一星期">一星期</option> <option value="一个月">一个月</option> <option value="半年">半年</option> <option value="一年">一年</option> </select></td> </tr> <tr> <td>案卷号:</td> <td><input class="easyui-textbox" type="text" name="acv.fileNum" style="width:253px;"> </input></td> <td>件号:</td> <td><input class="easyui-textbox" type="text" name="acv.partNum" style="width:270px;"> </input></td> </tr> <tr> <td>录入日期:</td> <td><input class="easyui-textbox" type="text" name="acv.date1" style="width:262px;"> </input></td> <td>至</td> <td><input class="easyui-textbox" type="text" name="acv.date2" style="width:270px;"> </input></td> </tr> </table> <input class="easyui-linkbutton" type="submit" value="Submit" /> <input class="easyui-linkbutton" type="button" value="Clear" onclick="clearForm()"/></form>
- 列表页面
<table width="500px" class="easyui-datagrid" data-options="url:‘datagrid_data1.json‘,method:‘get‘,border:false,singleSelect:true,fit:true,fitColumns:true"> <thead> <tr> <th data-options="field:‘itemid‘" width="70px">行号</th> <th data-options="field:‘kkkid‘" width="200px">题名(标题)</th> <th data-options="field:‘productid‘" width="120px">所在地</th> <th data-options="field:‘listprice‘" width="70px">文号</th> <th data-options="field:‘unitcost‘" width="70px">年度</th> <th data-options="field:‘attr1‘" width="70px">件号</th> <th data-options="field:‘status‘,align:‘center‘" width="70px">期限</th> <th data-options="field:‘control‘,align:‘center‘" width="150px">操作</th> </tr> <tbody> <c:forEach var="acv" items="${Archives}" varStatus="status"> <tr> <td>${acv.aid}</td> <td>${acv.title}</td> <td>${acv.location}</td> <td>${acv.dcNumber}</td> <td>${acv.year }</td> <td>${acv.partNum }</td> <td>${acv.outDate}</td> <td><div style="text-align:center;padding:1px;"> <a href="tag?acv.aid=${acv.aid}" class="easyui-linkbutton" style="height:20px;" >Update</a> <a href="delete?acv.aid=${acv.aid}" class="easyui-linkbutton" style="height:20px;">Delete</a> </div></td> </tr> </c:forEach> </tbody> </thead></table>
- 其他的包括有增删改查的操作都在这几个页面实现,想看完整代码的请下载源码。
八、结束语
这可以算是SSH中最简单的一个系统了,只是简单的实现了数据的增删改查的操作,没有其他的功能了。
通过这一个系统的实践,算是对SSH有一个初步的认识了,但还远远不够,估计连入门都算不上,路漫漫啊~。
相关资料:源码下载:https://github.com/cpacm/WebSystem
========================================
作者:cpacm
出处:(http://www.cnblogs.com/cpacm/p/4004504.html)
SSH的简单入门体验(Struts2.1+Spring3.1+Hibernate4.1)- 查询系统(下)