话说
上一篇博客,单纯用Hibernate写了图书管理系统,在接收参数方面,怎一个累字了得!
团结才是力量,合作促生共赢!框架滴世界也是如此。这篇博客简单总结下Hibernate+Struts2整合来实现上一篇博客的功能——图书管理系统
目录
1、整体框架及效果图
2、环境搭建
3、代码编写
4、页面
5、总结
开发环境:
IntelliJ IDEA(2017.2.5)
MySQL
Mavan web项目
1、整体框架及效果图
2、环境搭建
1)hibernate.cfg.xml
2)struts.xml
3)web.xml
1)hibernate.cfg.xml
这个配置达到这样几个目的:
连接数据库、实体类映射、自动创建表、打印SQL语句
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--配置MySQL数据库连接-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/sysmgr</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">119913</property>
<!--配置自动创建表、打印SQL语句-->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<!--配置实体映射-->
<mapping class="com.hmc.bookmgr.model.Book"></mapping>
</session-factory>
</hibernate-configuration>
2)struts.xml
这个配置达到这几个目的:
配置action、配置DMI
<?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>
<!--配置DMI-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<constant name="struts.devMode" value="true"/>
<package name="default" extends="struts-default">
<!--所有的方法都可以调用-->
<global-allowed-methods>regex:.*</global-allowed-methods>
<!--配置Action-->
<!--一定要注意,这个action类似Servlet,Servlet的name之所以
能够在页面直接访问,是因为Servlet是在web.xml中配置的,但是这里配置的位置
是struts.xml,如何和页面建立联系呢?过滤器!所以,还需要配置web.xml-->
<action name="*_*" class="com.hmc.bookmgr.action.{1}Action" method="{2}">
<result name="success">/{1}/{2}.jsp</result>
<!--为新增图书、修改和显示详情做跳转配置-->
<result name="redirectUrl" type="redirect">${url}</result>
</action>
</package>
<include file="example.xml"/>
<!-- Add packages here -->
</struts>
3)web.xml
过滤器,只有和struts.xml搭配,struts.xml才能发挥作用
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
3、代码编写
1)model
2)util
3)dao
4) action
1)model
Book
package com.hmc.bookmgr.model;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* User:Meice
* 2017/11/2
*/
@Entity
@Table(name = "book")
public class Book {
private int bookid;
private String bookname;
private String bookauthor;
private String bookpress;
private double bookprice;
private Date bookdate;
public Book() {}
public Book(int bookid,String bookname,String bookauthor,String bookpress
,double bookprice,Date bookdate) {
this.bookid = bookid;
this.bookname = bookname;
this.bookauthor = bookauthor;
this.bookpress = bookpress;
this.bookprice = bookprice;
this.bookdate = bookdate;
}
public Book(String bookname, String bookauthor, String bookpress, double bookprice, Date bookdate) {
this.bookname = bookname;
this.bookauthor = bookauthor;
this.bookpress = bookpress;
this.bookprice = bookprice;
this.bookdate = bookdate;
}
@Id
@GenericGenerator(name = "myid" ,strategy = "native")
@GeneratedValue(generator = "myid")
public int getBookid() {
return bookid;
}
public void setBookid(int bookid) {
this.bookid = bookid;
}
public String getBookname() {
return bookname;
}
public void setBookname(String bookname) {
this.bookname = bookname;
}
public String getBookauthor() {
return bookauthor;
}
public void setBookauthor(String bookauthor) {
this.bookauthor = bookauthor;
}
public String getBookpress() {
return bookpress;
}
public void setBookpress(String bookpress) {
this.bookpress = bookpress;
}
public double getBookprice() {
return bookprice;
}
public void setBookprice(double bookprice) {
this.bookprice = bookprice;
}
public Date getBookdate() {
return bookdate;
}
public void setBookdate(Date bookdate) {
this.bookdate = bookdate;
}
@Override
public String toString() {
return "Book{" +
"bookid=" + bookid +
", bookname='" + bookname + '\'' +
", bookauthor='" + bookauthor + '\'' +
", bookpress='" + bookpress + '\'' +
", bookprice=" + bookprice +
", bookdate=" + bookdate +
'}';
}
}
2)util
HibernateUtil
package com.hmc.bookmgr.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
/**
* User:Meice
* 2017/11/2
*/
public class HibernateUtil {
/**
* 得到session,关闭session
* 为方便调用,全部static!
*/
private static SessionFactory sessionFactory = null;
// A SessionFactory is set up once for an application!
static{
//这里要注意,默认配置文件名不要改,改了以后这里也要同步修改
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
try {
sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
} catch (Exception e) {
// The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
// so destroy it manually.
StandardServiceRegistryBuilder.destroy(registry);
}
}
/**
* 获取session
*/
public static Session getSession() {
Session session = sessionFactory.openSession();
return session;
}
/**
* 关闭session
*/
public static void closeSession(Session session){
session.close();
}
}
StringConvertInt
package com.hmc.bookmgr.util;
/**
* User:Meice
* 2017/11/2
*/
public class StringConvertInt {
/**
* 和以前一样,转换一下接受的id
*/
public static int getVal(String str){
if(str != null && !"".equals(str)) {
return Integer.parseInt(str);
}
return 0;
}
}
3)dao
BookDao
package com.hmc.bookmgr.dao;
import com.hmc.bookmgr.model.Book;
import com.hmc.bookmgr.util.HibernateUtil;
import com.opensymphony.xwork2.ActionContext;
import org.hibernate.Session;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* User:Meice
* 2017/11/2
*/
public class BookDao {
/**
* 实现增删改查
* 之前是方便Servlet调用 Struts2+ Hibernate整合后,方便Action调用,替代Servlet
* 为什么要替代呢?因为Servlet接收参数是在太繁琐;一旦参数多起来,接收晕乎了
*/
Session session = HibernateUtil.getSession();
//增
public int add(Book book) {
session.beginTransaction();
session.save(book);
session.getTransaction().commit();
return 1;
}
//删
public int del(int id) {
Book book = new Book();
book.setBookid(id);
session.beginTransaction();
session.delete(book);
session.getTransaction().commit();
return 1;
}
//改
/**
* 这里的修改,不在时给Id,因为struts2底层已经封装好,直接给对象
*/
public int update(Book book) {
session.beginTransaction();
session.update(book);
session.getTransaction().commit();
return 1;
}
//查-所有
@Test
public List<Book> getBooks() {
List<Book> books = session.createQuery("from Book").list();
return books;
/**
* 测试:
* Hibernate:select
book0_.bookid as bookid1_0_,
book0_.bookauthor as bookauth2_0_,
book0_.bookdate as bookdate3_0_,
book0_.bookname as bookname4_0_,
book0_.bookpress as bookpres5_0_,
book0_.bookprice as bookpric6_0_
from book book0_
Book{bookid=4, bookname='三国演义', bookauthor='罗贯中', bookpress='人民文学出版社', bookprice=77.77, bookdate=2017-11-02 07:46:14.0}
*/
}
//查-单个
@Test
public Book getBookById(int id) {
Book book = session.get(Book.class,id);
return book;
//测试结果无误
}
//查——分页显示
public List<Book> getBooksPager(int offset,int pageSize) {
List<Book> books = session.createQuery("from Book")
.setFirstResult(offset)
.setMaxResults(pageSize)
.list();
return books;
}
/**
* 查总条目数
*/
public int countBooks() {
Long longCount =(Long) session.createQuery("select count(bookid) from Book")
.uniqueResult();
int count = longCount.intValue();
return count;
}
}
4) action
BookAction
这里面把分页一块实现了,就避免在多出一个BookPage实体类
package com.hmc.bookmgr.action;
import com.hmc.bookmgr.dao.BookDao;
import com.hmc.bookmgr.model.Book;
import com.hmc.bookmgr.model.BookPager;
import com.hmc.bookmgr.util.StringConvertInt;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
import java.util.List;
/**
* User:Meice
* 2017/11/2
*/
public class BookAction implements ModelDriven<Book> {
BookDao bd = new BookDao();
private Book book;
private int pageIndex=1;//当前页
private int totalPage;//总页数
private int count;//总条目数
private int pageSize=15;//每页显示书目
private int offset;//偏移量 limit第一个参数
private String action;//用来区别调转到修改页面还是detail页面
/**
* 这里面实现原来Servlet的功能
* 接收参数、业务逻辑处理、页面跳转
*/
//显示图书
public String index() {
//接受参数
pageIndex = pageIndex<1? 1:pageIndex;
count = bd.countBooks();
/**
* 之前我们是在get()方法里面写的,发现接收不到参数,所以必须写在这里
*/
offset = (pageIndex-1)*pageSize;
//调用方法
List<Book> books = bd.getBooksPager(offset,pageSize);
//存储值
ActionContext.getContext().put("books",books);
//页面跳转
return "success";
}
/**
* 运行结果:
* Hibernate:
select count(book0_.bookid) as col_0_0_ from book book0_
Hibernate:
select book0_.bookid as bookid1_0_, book0_.bookauthor as bookauth2_0_,
book0_.bookdate as bookdate3_0_, book0_.bookname as bookname4_0_,
book0_.bookpress as bookpres5_0_, book0_.bookprice as bookpric6_0_
from book book0_ limit ?,?
*/
//增加图书
public String add() {
return "success";
}
public String doAdd() {
//接收参数
//调用方法
bd.add(book);
//
ActionContext.getContext().put("url","Book_index");
return "redirectUrl";
/**
* 运行结果
* Hibernate:
* insert into book (bookauthor, bookdate, bookname, bookpress, bookprice)
* values (?, ?, ?, ?, ?)
* Struts2多方便,参数根本不用像Servlet那样一个一个的接收,而且date类型都不用你处理
* 只要你写的符合YYYY-mm-dd格式就可以
*/
}
/**
* 显示图书信息
* @return
*/
public String detail() {
book = bd.getBookById(book.getBookid());
ActionContext.getContext().put("book",book);
return "success";
}
public String update() {
book = bd.getBookById(book.getBookid());
ActionContext.getContext().put("book",book);
return "success";
}
/**
* 执行修改
* @return
*/
public String doUpdate () {
//看看当年走过的弯路....
/* book.setBookname(book.getBookname());
book.setBookauthor(book.getBookauthor());
book.setBookprice(book.getBookprice());
book.setBookpress(book.getBookpress());
book.setBookdate(book.getBookdate());*/
bd.update(book);
ActionContext.getContext().put("url","Book_index");
return "redirectUrl";
}
/**
* 删除
*/
public String del() {
bd.del(book.getBookid());
ActionContext.getContext().put("url","Book_index");
return "redirectUrl";
}
public Book getModel() {
if(book == null) {
book = new Book();
}
return book;
}
/**
* 以下这些都是为了分页
* 因为Book的ModelDriven已经实现了,这些就我所知,
* 暂只能以这种方式接收连接传递过来的参数
* @return
*/
public int getPageIndex() {
return pageIndex;
}
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
public int getTotalPage() {
totalPage = (int)Math.ceil((double)count/pageSize);
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
4、页面
1) index.jsp——显示图书
<%--
User: Meice
Date: 2017/11/2
Time: 17:24
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>图书管理系统</title>
</head>
<body>
<table width="80%" border="1" align="center">
<caption>
<h2>Meice滴图书管理系统【Struts2+Hibernate】</h2>
</caption>
<thead>
<tr>
<th>编号</th>
<th>图书名称</th>
<th>图书作者</th>
<th>图书价格</th>
<th>出版社</th>
<th>出版日期</th>
<th>操作</th>
</tr>
</thead>
<tboday>
<c:forEach var="book" items="${books}">
<tr>
<td align="center">${book.bookid}</td>
<td>${book.bookname}</td>
<td>${book.bookauthor}</td>
<td>${book.bookprice}</td>
<td>${book.bookpress}</td>
<td>${book.bookdate}</td>
<td align="center">
<a href="Book_detail?bookid=${book.bookid}">详情</a>|
<a href="Book_update?bookid=${book.bookid}">修改</a>|
<a href="Book_del?bookid=${book.bookid}" onclick="return confirm('真的忍心删除么?')">删除</a>
</td>
</tr>
</c:forEach>
<tr align="center">
<td colspan="7">
<c:if test="${pageIndex>1}">
<a href="Book_index?pageIndex=1">首页</a>
<a href="Book_index?pageIndex=${pageIndex-1}">上一页</a>
</c:if>
<%--以下是有Bug的,不完美,暂且搁置,面子上过得去了,后续完善--%>
<c:if test="${pageIndex<totalPage-9}">
<c:forEach var="x" begin="${pageIndex}" end="${pageIndex+9}">
<a href="Book_index?pageIndex=${x}">${x}</a>
</c:forEach>
</c:if>
<c:if test="${pageIndex < totalPage}">
<a href="Book_index?pageIndex=${pageIndex+1}">下一页</a>
<a href="Book_index?pageIndex=${totalPage}">末页</a>
</c:if>
</td>
</tr>
</tboday>
</table>
<a href="Book_add">新增图书</a>
</body>
</html>
2)add.jsp——新增图书
<%--
User: Meice
Date: 2017/11/2
Time: 17:24
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>新增图书</title>
</head>
<body>
<form action="Book_doAdd" method="post">
<table width="40%" align="center" border="1">
<caption>
<h2>Meice-新增图书</h2>
</caption>
<tr>
<td>图书名称</td>
<td><input type="text" name="bookname"/></td>
</tr>
<tr>
<td>作者</td>
<td><input type="text" name="bookauthor"/></td>
</tr>
<tr>
<td>出版社</td>
<td><input type="text" name="bookpress"></td>
</tr>
<tr>
<td>价格</td>
<td><input type="text" name="bookprice" /></td>
</tr>
<tr>
<td>出版日期</td>
<td><input type="text" name="bookdate" /></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="新增"/></td>
</tr>
<tr>
<td colspan="3" align="center">
<a href="Book_index">返回主页面</a>
</td>
</tr>
</table>
</form>
</body>
</html>
3)update.jsp——修改图书
<%--
User: Meice
Date: 2017/11/2
Time: 17:25
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>图书修改</title>
<style type="text/css">
tr td{
text-align: center;
}
</style>
</head>
<body>
<form action="Book_doUpdate" method="post">
<input name="bookid" type="hidden" value="${book.bookid}">
<table width="40%" align="center" border="1">
<caption>
<h2>Meice-修改图书</h2>
</caption>
<tr>
<td>图书名称</td>
<td><input type="text" name="bookname" value="${book.bookname}"/></td>
</tr>
<tr>
<td>作者</td>
<td><input type="text" name="bookauthor" value="${book.bookauthor}"/></td>
</tr>
<tr>
<td>出版社</td>
<td><input type="text" name="bookpress" value="${book.bookpress}"></td>
</tr>
<tr>
<td>价格</td>
<td><input type="text" name="bookprice" value="${book.bookprice}"/></td>
</tr>
<tr>
<td>出版日期</td>
<td><input type="text" name="bookdate" value="${book.bookpress}"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="确认修改"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<a href="Book_index">返回主页面</a>
</td>
</tr>
</table>
</form>
</body>
</html>
4)detail.jsp——图书详情
<%--
User: Meice
Date: 2017/11/2
Time: 17:24
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>图书详情</title>
<style type="text/css">
tr td{
text-align: center;
}
</style>
</head>
<body>
<table width="40%" align="center" border="1">
<caption>
<h2>Meice-图书详情</h2>
</caption>
<tr>
<td align="center">图书名称</td>
<td>${book.bookname}</td>
</tr>
<tr>
<td align="center">作者</td>
<td>${book.bookauthor}</td>
</tr>
<tr>
<td align="center">出版社</td>
<td>${book.bookpress}</td>
</tr>
<tr>
<td align="center">价格</td>
<td>${book.bookprice}</td>
</tr>
<tr>
<td align="center">出版日期</td>
<td>${book.bookdate}</td>
</tr>
<tr>
<td colspan="2" align="center">
<a href="Book_index?pageIndex=${pageIndex}">返回主页面</a>
</td>
</tr>
</table>
</body>
</html>
5、总结
1、每一个框架的配置流程要炉火纯青,信手拈来。记忆是不靠谱的,知道快速寻找记忆,才是靠谱的。官网就是很好的方式。不用记忆过多东西,因为那些都是死的。知道怎么快速找到才最重要。
2、框架操作起来是简单了,配置要繁琐点,不过相比大数据,根本不算啥。所以,配置要细心,一定要配置全。配置全否,就要看对框架的理解是否深刻。自己操作就忘记配置web.xml的过滤器了。为什么会忘记呢?因为对struts2认识还是不够深刻。struts.xml中的action相当于Servlet,之前Servlet是在web.xml中配置的,所以一旦页面访问name,服务器就知道你想访问这个页面。但是,我们的action是配置在struts.xml中的,你在页面访问name,Web服务器怎么知道呢?所以嘛,中间的桥梁就是靠过滤器来实现的。所以要配置web.xml,这样理解,就根本不会忘记配置。
3、Hibernate优点:连接数据库方便、API方便、实体类映射方便
Struts2优点:Action接受参数、页面跳转(DMI)方便。
如果读者是从JDBC开始看在下的博客,并真的实际操作过,一定深有体会。
4、这次整合遇到的问题是:分页的参数怎么在BookAction中传递。最后想到的办法是,按照struts2的第一种接收参数的方式,把分页的几个参数全部定义为变量,并且生成get()、set()方法,这样链接传过来的参数就可以直接接收了。因为没法实现2个不同的ModelDrivet呢。
5、增加和修改的时候,页面跳转用到了动态结果集,很灵活的跳转方式。
6、分页中的末页还有bug,暂且搁置。
好了,亲爱的各位读者,下期再会!
本文通过实战演示Struts2与Hibernate框架整合的过程,包括环境搭建、代码编写及页面展示等步骤,实现了一个简单的图书管理系统。
389





