写在前面:
接触SSH框架有一段时间了。在整合实战的过程中遇到了各种各样的问题,最后都一一解决了。
下面记录一个SSH框架整合实战的小演示,这个演示旨在记录学习SSH框架的艰辛过程。
重点知识:
1,在Eclipse中下手动搭建SSH框架,并把SessionFactory的交由春天来管理。
2,使用休眠插件反向生成实体类和关系映射文件。
3,学习SSH框架整合的基本架构。
测试环境:
jdk 1.8.0_74
tomcat 8.0
日食霓虹灯
struts2 2.3.4.1
春天3.2.1
休眠4.1.9
一,创建一个动态的网络项目:
打开Eclipse,文件>新建>动态Web项目(如果此处没有Dynamic Web Project选项的话,在最下方的其他选项里搜索一下它就有了)
填写好项目名称之后,记得选择目标运行时为Apache Tomcat v8.0,这里就用web3.1的版本进行测试吧。点击下一步>
点击下一步>
记得这里一定要勾选生成web.xml部署描述符选项生成web.xml文件。点击完成>
这样我们的项目就基本创建完毕了,大致的目录结构如下图:
二,复制SSH框架整合所必需的核心罐包到WEB-INF / lib中文件夹下:
全选复制上图中所有的JAR包,粘贴到下图中的LIB文件夹下,如图所示:
三,复制SSH框架所必需的配置文件到的src文件夹下:
全选复制上图中所有的配置文件,粘贴到下图中的SRC文件夹中,如图所示:
这里需要说明一点,因为我们把SessionFactory的交由春天来管理了,所以applicationContext.xml的文件也就取代了hibernate.cfg.xml的文件,那么这里不需要再创建hibernate.cfg.xml的文件。
四,在WEB-INF / web.xml文件文件中配置的Struts2的核心过滤器和弹簧的监听器:
这里需要说明一点,因为我们把applicationContext.xml文件放在了src文件夹下,所以这里<param-value>classpath:applicationContext.xml</param-value>标签的classpath:就说明默认去src文件夹下读取配置文件。假设我们把applicationContext.xml文件放在了WEB-INF文件夹下,那么这里的标签内容就要修改为<param-value>WEB-INF/applicationContext.xml</param-value>,这里需要注意。
这样我们的SSH框架整合的Demo就创建完毕了。
五、建立数据表结构,并配置数据库连接参数:
这个小Demo要实现一个搜索的功能,主要需求如下:
1、实现通过作者搜索该作者的所有作品。
2、实现诗词名称搜索唐诗全文并显示。
3、实现通过诗歌的名句搜索该唐诗的作者、题目和全文。
下面先使用SQLyog工具建立数据表结构。这里需要说明一点,由于我们后期会使用Hibernate插件反向生成实体类和关系映射文件,所以在这里建立数据库表结构的时候,键与键之间关系的正确配置决定了以后反向生成实体类和关系映射文件的成败。
数据库结构如下图所示,数据库名称为tangshi,注意为了防止后期出现中文乱码,这里应当设置字符编码集为utf-8,有两张数据表分别为:poets、poetries。主键id与poet_id有一个关系,这个配置很重要。
数据表结构建立完成以后,我们打开Eclipse配置数据库连接参数,Windows>Data Source Explorer,如下图所示:
在Data Source Explorer窗口中鼠标右击选择new,新建一个数据库连接。数据库类型选择MySQL,name可以自行设置,这里设置为DemoMySQL。如下图所示:
点击下一步>,此处点击新驱动程序定义按钮,添加一个数据库连接驱动,如下图所示:
名称/类型这里选择MySQL5.1版本,JAR列表这里点击添加JAR / ZIP添加一个MySQL的JDBC驱动,属性这里配置数据库连接参数,如下图所示:
点击OK>,这里说明一点,如图所示最下方有两个选项。第一个选项的意思是在配置完数据库连接参数以后马上连接到数据库,第二个选项的意思是在每次启动的Eclipse的时候自动连接到数据库这里自行设置,如下图所示:
再检查一下,确认无误以后点击完成>,如下图所示是我们建立好的数据库连接,依次展开图示的目录就可以看到我们事先建立好的数据表结构了:
六,使用Hibernate的插件反向生成实体类和关系映射文件:
在Eclipse下载JBoss-Tools插件,打开Eclipse,帮助> Eclipse Marketplace,在搜索框里输入JBoss-Tools敲回车进行搜索,得到结果,如下图所示:
点击安装进行安装。默认下载JBoss-Tools全部的插件即可,这个过程中会弹出一个询问是否同意加载的界面,点击我接受,然后一直点击OK直到Eclipse自动重启即可。
安装完成后我们依次点击Windows>显示视图>其他,在搜索框里输入Hibernate进行搜索,打开Hibernate配置窗口,如图所示:
在Hibernate配置窗口中新建一个Hibernate配置,右键选择添加Configuration.Main这里设置Hibernate Version为4.0,Project为Demo,数据库连接为DemoMySQL.Options这里设置数据库方言为MySQL,然后点击OK。如下图所示:
这时我们的Hibernate Configuration窗口里会多出一个配置,依次展开图示的目录就可以看到我们事先建立好的数据表结构了:
接下来我们在工具栏中添加Hibernate按钮,打开Eclipse,Windows>Perspective>Customize Perspective,在Action Set Availability选项卡中找到并勾选Hibernate Code Generation按钮,点击OK。如下图所示:
这时我们的工具栏就会出现一个与Hibernate相关的按钮,点击Hibernate Code Generation Configuration选项,在弹出的菜单中按如下图所示的方法依次选择Main、Exporters、Common进行配置。
这里说明一点,在reveng.xml选项卡中,需要点击Setup新建一个hibernate.reveng.xml文件,保存文件的目录选择对应工程下的src文件夹,如下图所示:
点击Next>,这里说明一点,在Datebase schema选项卡的下方点击Refresh按钮,会刷新出所有的数据表。
依次选定数据表并点击Include按钮将其添加到Table filters选项卡中,如下图所示:
点击Finish>,Common选项卡的设置如下图所示,点击Run>
这时我们的工程src文件夹下会自动生成Hibernate实体类和与其对应的关系映射文件,如下图所示:
实体类文件如下:
Poets.java
简单来说,Poets类只有两个属性,分别为id和name,创建它们的get()、set()方法即可。
[java] view plain copy
- package com.csdn.entity;
- 公共 类 Poets 实现 java.io.Serializable {
- private static final long serialVersionUID = 1L;
- private Integer id;
- 私有 字符串名称;
- 公共 诗人(){
- }
- public Poets(String name){
- 这个 .name =名字;
- }
- public Integer getId(){
- 返回 此 .id;
- }
- public void setId(Integer id){
- 这个 .id = id;
- }
- public String getName(){
- 返回 此 .name;
- }
- public void setName(String name){
- 这个 .name =名字;
- }
- }
Poetries.java
简单来说,Poetries类有四个属性,分别为id、poets、title和content,创建它们的get()、set()方法即可。
[java] view plain copy
- package com.csdn.entity;
- public class Poetries implements java.io.Serializable {
- private static final long serialVersionUID = 1L;
- private Integer id;
- private Poets poets;
- private String content;
- private String title;
- public Poetries() {
- }
- public Poetries(Poets poets, String content, String title) {
- this.poets = poets;
- this.content = content;
- this.title = title;
- }
- public Integer getId() {
- return this.id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public Poets getPoets() {
- return this.poets;
- }
- public void setPoets(Poets poets) {
- this.poets = poets;
- }
- public String getContent() {
- return this.content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- public String getTitle() {
- return this.title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- }
关系映射文件如下:
Poets.hbm.xml
[html] view plain copy
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.csdn.entity.Poets" table="poets" catalog="tangshi">
- <id name="id" type="java.lang.Integer">
- <column name="id" />
- <generator class="identity" />
- </id>
- <property name="name" type="string">
- <column name="name" />
- </property>
- </class>
- </hibernate-mapping>
Poetries.hbm.xml
[html] view plain copy
- <?xml version="1.0"?>
- <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
- <hibernate-mapping>
- <class name="com.csdn.entity.Poetries" table="poetries" catalog="tangshi">
- <id name="id" type="java.lang.Integer">
- <column name="id" />
- <generator class="identity" />
- </id>
- <many-to-one name="poets" class="com.csdn.entity.Poets"
- fetch="select">
- <column name="poet_id" />
- </many-to-one>
- <property name="content" type="string">
- <column name="content" length="65535" />
- </property>
- <property name="title" type="string">
- <column name="title" />
- </property>
- </class>
- </hibernate-mapping>
从以上配置文件中可以清楚的看出Eclipse已经自动识别出了两个类之间的多对一关系。
七、在Spring的核心配置文件applicationContext.xml文件下配置与Hibernate相关的参数:
applicationContext.xml
[html] view plain copy
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
- xmlns:tx="http://www.springframework.org/schema/tx">
- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
- <property name="url"
- value="jdbc:mysql://localhost:3306/tangshi?useUnicode=true&characterEncoding=utf-8">
- </property>
- <property name="username" value="root"></property>
- <property name="password" value="root"></property>
- </bean>
- <bean id="sessionFactory"
- class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
- <property name="dataSource">
- <ref bean="dataSource" />
- </property>
- <property name="hibernateProperties">
- <props>
- <prop key="hibernate.dialect">
- org.hibernate.dialect.MySQLDialect
- </prop>
- </props>
- </property>
- <property name="mappingResources">
- <list>
- <value>com/csdn/entity/Poetries.hbm.xml</value>
- <value>com/csdn/entity/Poets.hbm.xml</value>
- </list>
- </property>
- </bean>
- <bean id="transactionManager"
- class="org.springframework.orm.hibernate4.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory" />
- </bean>
- <tx:annotation-driven transaction-manager="transactionManager" />
- </beans>
八、建立项目所必需的包和类。
SSH框架整合的项目结构一般有三层,分别是Dao层、Service层、Action层。
下面我们依次来创建它们。这里说明一点,Dao层和Service层需要用接口的方式来写,然后用实现类去分别实现它们。项目结构图下图所示:
com.csdn.dao包,其中包含SearchDao.java接口,用来书写数据库查询的方法。
com.csdn.dao.impl包,其中包含SearchDaoImpl.java类,用来实现SearchDao.java接口。
com.csdn.service包,其中包含SearchService.java接口,用来书写业务逻辑。
com.csdn.service.impl包,其中包含SearchServiceImpl.java类,用来实现SearchService.java接口。
com.csdn.action包,其中包含SearchAction.java类,用来书写控制跳转逻辑。
九、编写具体代码实现:
SearchDao.java
这里说明一下,Dao层书写了三个方法,分别是findByName、findByTitle、findByContent,分别实现了三个我们的主要需求。
[java] view plain copy
- package com.csdn.dao;
- import java.util.List;
- public interface SearchDao {
- public List<String> findByName(String name);
- public List<String> findByTitle(String title);
- public List<String> findByContent(String content);
- }
SearchDaoImpl.java
分别实现findByName、findByTitle、findByContent三个方法。
[java] view plain copy
- package com.csdn.dao.impl;
- import java.util.List;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import com.csdn.dao.SearchDao;
- public class SearchDaoImpl 实现 SearchDao {
- private SessionFactory sessionFactory;
- private List <String>列表;
- public List <String> getList(){
- 返回 清单;
- }
- public void setList(List <String> list){
- 这个 .list = list;
- }
- public SessionFactory getSessionFactory(){
- return sessionFactory;
- }
- public void setSessionFactory(SessionFactory sessionFactory){
- 这个 .sessionFactory = sessionFactory;
- }
- @SuppressWarnings({ “unchecked” })
- @覆盖
- public List <String> findByName(String name){
- 会话会话= sessionFactory.openSession();
- 交易ts = session.beginTransaction();
- String sql = “select b.title from poetries b left join poets a on b.poet_id = a.id where a.name =?” ;
- 查询query = session.createSQLQuery(sql).setString(0,name);
- list = query.list();
- ts.commit();
- session.close();
- 返回 清单;
- }
- @SuppressWarnings(“未选中”)
- @覆盖
- public List <String> findByTitle(String title){
- 会话会话= sessionFactory.openSession();
- 交易ts = session.beginTransaction();
- String sql = “从title =?的poetries中选择内容” ;
- 查询query = session.createSQLQuery(sql).setString(0,title);
- list = query.list();
- ts.commit();
- session.close();
- 返回 清单;
- }
- @SuppressWarnings(“未选中”)
- @覆盖
- public List <String> findByContent(String content){
- 会话会话= sessionFactory.openSession();
- 交易ts = session.beginTransaction();
- String sql = “选择a.content作为内容,a.title作为标题,b.name作为名称来自poetries a inner join poets b on a.poet_id = b.id where acontent like?” ;
- Query query = session.createSQLQuery(sql).setString(0, "%" + content + "%");
- list = query.list();
- ts.commit();
- session.close();
- return list;
- }
- }
SearchService.java
[java] view plain copy
- package com.csdn.service;
- import java.util.List;
- public interface SearchService {
- public List<String> findByName(String name);
- public List<String> findByTitle(String title);
- public List<String> findContent(String content);
- }
SearchServiceImpl.java
[java] view plain copy
- package com.csdn.service.impl;
- import java.util.List;
- import com.csdn.dao.SearchDao;
- import com.csdn.service.SearchService;
- public class SearchServiceImpl implements SearchService {
- private SearchDao searchDaoImpl;
- public SearchDao getSrarchDaoImpl() {
- return searchDaoImpl;
- }
- public void setSearchDaoImpl(SearchDao searchDaoImpl) {
- this.searchDaoImpl = searchDaoImpl;
- }
- @Override
- public List<String> findByName(String name) {
- return searchDaoImpl.findByName(name);
- }
- @Override
- public List<String> findByTitle(String title) {
- return searchDaoImpl.findByTitle(title);
- }
- @Override
- public List <String> findContent(String content){
- return searchDaoImpl.findByContent(content);
- }
- }
SearchAction.java
由于后期我们的JSP页面会书写<选择> <选项> <选项/> </选择>标签用来让用户选择搜索类型,所以这里我们需要加入一个成员变量检索类别。利用浏览()方法实现调用不同的查询方法。
[java] view plain copy
- package com.csdn.action;
- import java.util.List;
- import java.util.Map;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- import com.csdn.service.SearchService;
- @SuppressWarnings(“serial”)
- 公共 类 SearchAction 扩展 ActionSupport {
- private static final Object SEARCH_TYPE_NAME = “1” ;
- private static final Object SEARCH_TYPE_TITLE = “2” ;
- private SearchService searchService;
- private List <String>列表;
- 私有 字符串内容;
- private String searchType;
- public SearchService getSearchService(){
- return searchService;
- }
- public static Object getSearchTypeName(){
- 返回 SEARCH_TYPE_NAME;
- }
- public static Object getSearchTypeTitle(){
- 返回 SEARCH_TYPE_TITLE;
- }
- public List <String> getList(){
- 返回 清单;
- }
- public void setList(List <String> list){
- 这个 .list = list;
- }
- public String getContent(){
- 返回 内容;
- }
- public void setContent(String content){
- 这个 .content = content;
- }
- public void setSearchService(SearchService searchService){
- 这个 .searchService = searchService;
- }
- public String getSearchType(){
- return searchType;
- }
- public void setSearchType(String searchType){
- 这个 .searchType = searchType;
- }
- @SuppressWarnings(“未选中”)
- public String browseFind() throws Exception {
- if (searchType.equals(SEARCH_TYPE_NAME)){
- list = searchService.findByName(content);
- } else if (searchType.equals(SEARCH_TYPE_TITLE)){
- list = searchService.findByTitle(content);
- } else {
- list = searchService.findContent(content);
- }
- @SuppressWarnings(“rawtypes”)
- Map request =(Map)ActionContext.getContext()。get(“request”);
- request.put(“list”,list);
- 返回 SUCCESS;
- }
- }
十,编写前端JSP页面的具体实现:
这里说明一点,index.jsp的页面我们使用了两个重要的标签。
一个是HTML标签<选择> </选择>,一个是struts2的标签<S:迭代> </ s的:迭代>。
前者的作用是给用户一个可以选择搜索类型的搜索框,后者的作用是利用迭代器遍历查询到的列表集合。
- <%@ page language = “java” import = “java.util。*” pageEncoding = “UTF-8”%>
- <%@ taglib prefix = “s” uri = “/ struts-tags”%>
- <%
- String path = request .getContextPath();
- String basePath = request .getScheme()+“://”+ request.getServerName()+“:”+ request.getServerPort()
- +路径+“/”;
- %>
- <!DOCTYPE HTML PUBLIC“ - // W3C // DTD HTML 4.01 Transitional // EN” >
- < html >
- < 头>
- < base href = “<%= basePath%>” >
- < title >唐诗搜索引擎</ title >
- < meta http-equiv = “pragma” content = “no-cache” >
- < meta http-equiv = “cache-control” content = “no-cache” >
- < meta http-equiv = “expires” content = “0” >
- < meta http-equiv = “keywords” content = “keyword1,keyword2,keyword3” >
- < meta http-equiv = “description” content = “这是我的页面” >
- <! -
- <link rel =“stylesheet”type =“text / css”href =“styles.css”>
- - >
- </ head >
- < body >
- < div >唐诗三百首</ div >
- < div >
- < form action = “SearchAction” method = “post” >
- < select name = “searchType” id = “searchType” >
- < option value = 1 >作者</ option >
- < option value = 2 >题目</ option >
- < option value = 3 >名句</ option >
- </ select > < input type = “text” name = “content” > < input type = “submit”
- value = “搜索” >
- </ form >
- </ div >
- < div >
- < table >
- < s:if test = “searchType == 1” >
- < s:iterator value = “#request.list” id = “content” >
- < s:property value = “#content” />
- </ s:iterator >
- </ s:if >
- < s:if test = “searchType == 2” >
- < s:iterator value = “#request.list” id = “content” >
- < s:property value = “#content” />
- </ s:iterator >
- </ s:if >
- < s:if test = “searchType == 3” >
- < s:iterator value = “#request.list” id = “content” >
- < s:property value = “#content” />
- </ s:iterator >
- </ s:if >
- </ table >
- </ div >
- </ body >
- </ html >
十一,Struts2的的核心配置文件struts.xml中与春天的核心配置文件applicationContext.xml的文件的书写:
在struts.xml
这里说明一点,由于<动作> </动作>的实例化工作交给了弹簧来管理,所以此处的类= “searchAction” 我们就不需要书写<动作> </动作>的全限定名了。
- <?xml version = “1.0” encoding = “UTF-8” ?>
- <!DOCTYPE struts PUBLIC
- “ - // Apache Software Foundation // DTD Struts Configuration 2.5 // EN”
- “http://struts.apache.org/dtds/struts-2.5.dtd” >
- < struts >
- < package name = “default” namespace = “/” extends = “struts-default” >
- < action name = “SearchAction” class = “searchAction” method = “browseFind” >
- < result name = “success” > /index.jsp </ result >
- </ action >
- </ package >
- </ struts >
applicationContext.xml中
- <?xml version = “1.0” encoding = “UTF-8” ?>
- < beans xmlns = “http://www.springframework.org/schema/beans”
- xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance” xmlns:p = “http://www.springframework.org/schema/p”
- xsi:schemaLocation = “http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema / tx http://www.springframework.org/schema/tx/spring-tx.xsd“
- xmlns:tx = “http://www.springframework.org/schema/tx” >
- < bean id = “dataSource” class = “org.apache.commons.dbcp.BasicDataSource” >
- < property name = “driverClassName” value = “com.mysql.jdbc.Driver” > </ property >
- < property name = “url”
- value = “jdbc:mysql:// localhost:3306 / tangshi?useUnicode = true&characterEncoding = utf-8” >
- </ property >
- < property name = “username” value = “root” > </ property >
- < property name = “password” value = “root” > </ property >
- </ bean >
- < bean id = “sessionFactory”
- class = “org.springframework.orm.hibernate4.LocalSessionFactoryBean” >
- < property name = “dataSource” >
- < ref bean = “dataSource” />
- </ property >
- < property name = “hibernateProperties” >
- < 道具>
- < prop key = “hibernate.dialect” >
- org.hibernate.dialect.MySQLDialect
- </ prop >
- </ props >
- </ property >
- < property name = “mappingResources” >
- < list >
- < value > com / csdn / entity / Poetries.hbm.xml </ value >
- < value > com / csdn / entity / Poets.hbm.xml </ value >
- </ list >
- </ property >
- </ bean >
- < bean id = “searchDaoImpl” class = “com.csdn.dao.impl.SearchDaoImpl” >
- < property name = “sessionFactory” ref = “sessionFactory” > </ property >
- </ bean >
- < bean id = “searchService” class = “com.csdn.service.impl.SearchServiceImpl” >
- < property name = “searchDaoImpl” ref = “searchDaoImpl” > </ property >
- </ bean >
- < bean id = “searchAction” class = “com.csdn.action.BaseAction” >
- < property name = “searchService” ref = “searchService” > </ property >
- </ bean >
- < bean id = “transactionManager”
- class = “org.springframework.orm.hibernate4.HibernateTransactionManager” >
- < property name = “sessionFactory” ref = “sessionFactory” />
- </ bean >
- < tx:annotation-driven transaction-manager = “transactionManager” />
- </ beans >
十二,效果展示: