经典项目,练手必备。
- 图书管理系统
需求分析(大致,并不专业):1.需要有用户管理;
1.1 用户注册;
1.2 用户登录;
1.3 用户信息修改;
1.4 用户修改密码;
2.需要有书本管理;
2.1 添加书籍;
2.2 借出书籍;
2.3 归还书籍;
2.4 修改/更新书籍信息;
3.需要权限管理;
3.1 普通用户与管理员的区别;
3.2 拥有不同权限可浏览不同的页面;
实现技术:1.struts2表现层框架;
2.hibernate持久层框架;
3.tomcat web容器;
4.c3p0数据库连接池;
5.msql数据库;
6.jquery开源包;
7.ajax技术;
8.css/html页面设计。
- 准备阶段
配置环境:配置struts2,hibernate环境,配上tomcat服务器,安装mysql服务器;
表设计:本项目设计四张表:user,book,borrow,description
系统总体设计:
页面设计:
- 实现
采用mvc的设计模式,页面请求到action,action开启服务service,service调用dao来操作数据库。最后将结果返回到页面上呈现。
tips:1.连接池使用listener启动,因为它启动得最早,而且spring也是使用listener来初始化bean工厂;
2.filter用来做权限控制;
3.action实现modeldriven接口,需要新建一些映射表单的类;
4.业务写多了会无聊,并且逻辑都一样,所以我选择只实现了一半;
页面图:
index.jsp
register.jsp
findpassword.jsp
message页面,统一样式
main.jsp
userBook.jsp
就实现了这些功能,写业务比算法无聊很多,所以大致掌握了就行了,反正练手。
- 技术笔记
页面延迟n秒跳转
//自动跳转的轮子 function delayURL(url, time) { setTimeout("top.location.href='" + url + "'", time); }
在html中加入
<script type="text/javascript"> delayURL("findPasswd.jsp", 3000); </script>
初始化请求
在页面载入成功后请求服务器拿初始化数据,并生成表格。
//初始化请求--将当前页和总页面初始化 和 list $(document).ready(function(){ pagerRequest(currentPage); });
使用数据生成表格。
//将数据放在页面上 function putOnTable(list) { var table = $('#content'); $("#content tr:not(:first)").remove(); for ( var k in list) { var tr = $("<tr></tr>"); tr.appendTo(table); var book = new Object(); var td; book.bookid = list[k]['bookid']; book.bookname = list[k]['bookname']; book.authorname = list[k]['authorname']; book.publisher = list[k]['publisher']; book.pub_date = list[k]['pub_date']; td = $("<td>" + book.bookid + "</td>"); td.appendTo(tr); td = $("<td>" + book.bookname + "</td>"); td.appendTo(tr); td = $("<td>" + book.authorname + "</td>"); td.appendTo(tr); td = $("<td>" + book.publisher + "</td>"); td.appendTo(tr); td = $("<td>" + book.pub_date + "</td>"); td.appendTo(tr); td = $("<td><button id=btn"+book.bookid +">借书</button>|<button value=''>查看详情</button>"); td.appendTo(tr); addEvent('btn'+book.bookid,book.bookid);//此处添加事件 } }
分页查询
//点击按钮发送ajax请求 function pagerRequest(need) { $.post("pager", "need=" + need , function(result) { size = result['size']; count = result['count']; booklist = result['booklist']; $('#current').text(currentPage); var n1; var n2; n1 = count / size; n2 = count % size; n1 = Math.floor(n1); pageNumber = n1; if (n2 !== 0) pageNumber = pageNumber + 1; $('#total').text(pageNumber); putOnTable(booklist); }); }
<!-- 分页查询动作--> <action name="pager" class="Action.BookPageSelectAction" method="Pager"> <result type="json"> <!-- 这里指定将被Struts2序列化的属性,该属性在action中必须有对应的getter方法 --> <param name="root">dataMap</param> </result> </action>
package Action; import java.util.HashMap; import java.util.List; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import Model.book; import Service.bookService; public class BookPageSelectAction extends ActionSupport{ private HashMap<String,Object> dataMap; private List<book> bookList; private int size=10; public List<book> getUserList() { return bookList; } public void setUserList(List<book> bookList) { this.bookList = bookList; } public HashMap<String, Object> getDataMap() { return dataMap; } public void setDataMap(HashMap<String, Object> dataMap) { this.dataMap = dataMap; } //ajax请求页 public String Pager(){ dataMap = new HashMap<String,Object>(); bookService pager = new bookService(); int count = pager.getBookCount(); String req = ServletActionContext.getRequest().getParameter("need"); Integer value = new Integer(req); int need = value.intValue(); List list = pager.pageSelectService(need, size); dataMap.put("booklist",list); dataMap.put("size", size); dataMap.put("count", count); return SUCCESS; } }
//分页查询 public List pageSelectService(int start,int size){ Session session = SFactoryGenerator.getSession(); Transaction tx = session.beginTransaction(); List list = null; try{ int need = (start-1)*size; list = bookDAO.pageSelect(session,need, size); }catch (Exception e) { // TODO: handle exception tx.rollback(); }finally{ session.close(); } return list; }
//分页查询 public static List<book> pageSelect(Session session,int start,int size){ String hql = "from book"; Query<?> query = session.createQuery(hql); query.setFirstResult(start);//开始索引 query.setMaxResults(size);//取几条 List list = query.list(); return list; }
删除所有表格条目,只留下表头
$("#content tr:not(:first)").remove();
绑定事件
$('#'+btnid).bind("click",function(){});
添加通知栏
别人的轮子
//添加通知框 function pop_init(title,content) { //取当前浏览器窗口大小 var windowWidth=document.body.clientWidth; var windowHeight=document.body.clientHeight; //弹窗的大小 var weight=250; var height=132; $("body").append( "<div id='pop_div'style='display:none;position:absolute;border:1px solid #e0e0e0;z-index:99;"+weight+"px;height:"+height+"px;top:"+(windowHeight-height-132)+"px;left:"+(windowWidth-weight)+"px'>"+ "<div style='line-height:32px;background:#F4A460;border-bottom:1px solid #e0e0e0;font-size:14px;padding:0 0 0 10px;'>" + "<div style='float:left;'><b>"+title+"</b></div><div style='float:right;cursor:pointer;'><b onclick='pop_close()'>×</b></div>" + "<div style='clear:both'></div>"+ "</div>" + "<div id='content' style='background:#EED8AE;height:100px;'>" + content+ "</div>"+ "</div>" ); } function pop_close(){ $('#pop_div').fadeOut(400); }
前端校验
非空校验,长度校验,用户名是否存在校验等等
/** * 用作注册校验以及ajax服务端校验 */ //非空校验 长度校验 function verificationUsername(){ var data = $('#username').val(); if(data.length === 0) { $('#registerErrorMsg1').text("用户名不能为空"); return false; } else if(data.length <3 || data.length>12) { $('#registerErrorMsg1').text("长度需要在3-12位"); return false; } return true; } //密码校验 var passwordVer1 = false; var passwordVer2 = false; function verificationPassword(){ var data = $('#password').val(); var again = $('#password1').val(); if(data.length === 0) { $('#registerErrorMsg2').text("密码不能为空"); return ; } else if(data.length <6 || data.length>20) { $('#registerErrorMsg2').text("长度需要在6-20位"); return ; } passwordVer1 = true; } //ajax校验 function ServerVerification(){ var data = $('#username').val(); $.get("userExist","username="+data,function(result){ if(result === "true"){ $('#registerErrorMsg1').text("用户名已存在"); return false; } else { $('#registerErrorMsg1').text("此用户名可以注册"); return true; } }); } //用户名校验 $(document).ready(function(){ $('#username').blur(function(){ if(verificationUsername()) ServerVerification(); }); }); $(document).ready(function(){ $('#username').focus(function(){ $('#registerErrorMsg1').text(""); }); }); //密码校验 $(document).ready(function(){ $('#password').blur(function(){ verificationPassword(); }); }); $(document).ready(function(){ $('#password').focus(function(){ $('#registerErrorMsg2').text(""); }); }); //两次输入密码校验 $(document).ready(function(){ $('#password1').blur(function(){ if($('#password1').val() !== $('#password').val()) { $('#registerErrorMsg2').text("密码输入不一致"); return ; }else { $('#registerErrorMsg2').text(""); passwordVer2 = true; } }); }); //提交时候需要验证 $(document).ready(function(){ $("#registerform").submit(function(){ verificationPassword(); console.log("-----3------"); if(verificationUsername() && passwordVer1 && passwordVer2) { return true; }else return false; }); });
查找书本
使用hql的都是这样写,被划了横线了好像是过期方法
//查找书本 public static book findByName(Session session,String name){ String hql = "from book where bookname = ?"; Query<?> query = session.createQuery(hql); query.setParameter(0, name); List list = query.list(); book book = null; if(list.size() != 0) book =(book) list.get(0); return book; }
使用count计算条目
//获取书本的条数 public static int getBookCount(Session session){ String hql="SELECT COUNT(*) FROM book"; Query<?> query = session.createQuery(hql); return ((Number)query.uniqueResult()).intValue(); }
自定类联合查询
不会join,用的where and。新建一个类不需要添加mapping也能封装成object。
//获取借书列表 public static List user_bookList(Session session,int userid){ String hql = "select new Model.user_book(b.bookid,b.bookname,b.publisher,bo.date) from book b,borrow bo where bo.user_id = ? and bo.book_id = b.bookid"; Query query =session.createQuery(hql); query.setParameter(0, userid); List list = query.list(); if(list.size() == 0) return null; return list; }
request
request的attribute和parameter是两个东西,已parameter是跟在请求后面的参数,attribute是类似于session这种存储在request范围内的属性。
标准的获取形式为
//获取请求响应 HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse();
- 总结
个人觉得不写之前很简单,写了之后也很简单。但是写的过程有很多的不懂,所以项目还是要做一下不然抱着demo不知道怎么用。因为s和h框架很少用了,所以不专注于写这个项目了。关键是网站的大部分的功能如何构建,换了框架和数据库一样是这样实现。自己做一做小项目会增长很多的本事。写了代码也要多多总结,比如刚写css的时候就感觉越写越多,很多重复功能,因为不主攻前端,所以让它变成臭鸡蛋吧,这样的感觉。
action的配置我觉得挺方便的,反而是注释开发,好像不能一眼看完所有的controller,然而action太侵入性,所以已经有些过时。hibernate用了之后我觉得各有利弊吧,我还是喜欢jdbc的感觉。接下来就该细致地写spring的项目了。