【Java EE 学习 56】【酒店会员管理系统技术点总结】
一、树状菜单加载
这是js的一个典型应用,使用zTree插件能够完成该项任务http://www.ztree.me/v3/main.php
我是用的版本:zTree2.5
使用方法:
1 <%@ page language="java" isELIgnored="false" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 4 <html> 5 <head> 6 <meta http-equiv="content-type" content="text/html;charset=utf-8"> 7 <title>导航菜单</title> 8 <link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/menu.css" type="text/css"> 9 <link rel="stylesheet" href="${pageContext.servletContext.contextPath}/css/ztree/zTreeStyle/zTreeStyle.css" type="text/css"> 10 <%@ include file="/jsp/common.jsp" %> 11 <script type="text/javascript" src="${pageContext.servletContext.contextPath}/js/ztree/jquery-ztree-2.5.js"></script> 12 <script type="text/javascript" src="${pageContext.servletContext.contextPath}/js/menu_tree.js"></script> 13 </head> 14 15 <body> 16 <TABLE border=0 height=600px align=left> 17 <TR> 18 <TD width=230px align=left valign=top style="BORDER-RIGHT: #999999 1px dashed"> 19 <ul id="tree" class="tree" style="width:230px; overflow:auto;"></ul> 20 </TD> 21 </TR> 22 </TABLE> 23 </body> 24 </html>
核心代码:
<TABLE border=0 height=600px align=left> <TR> <TD width=230px align=left valign=top style="BORDER-RIGHT: #999999 1px dashed"> <ul id="tree" class="tree" style="width:230px; overflow:auto;"></ul> </TD> </TR> </TABLE>
最重要的就是ul标签了,该标签的id属性值为tree,是加载树形插件的关键。
树形菜单的加载方式分为两种,一种是一次性加载,另外一种就是单击触发式的加载。一次性加载的方法比较简单,但是面对大数据菜单的时候响应速度慢,用户体验很不好,所以这里使用了单击触发式的加载。
var tree={ zTree:'',//通过调用post方法返回的对象 pNode:'',//父节点 setting:{ isSimpleData: true, treeNodeKey: "mid", treeNodeParentKey: "pid", showLine: true, root:{ isRoot:true, nodes:[] }, callback:{ expand:function(event, treeId, treeNode){ tree.pNode=treeNode;//共享之后就不需要传递参数了。 treeNode.isParent=true, tree.loadNodeByPNode(); } } }, //加载树根的方法 loadRoot:function(){ var parameters={ //首先加载父节点为0的树,即第一级目录 pid:0 }; $.post("Menuitem_showMenuItemsByPid.action",parameters,function(data){ tree.zTree=$("#tree").zTree(tree.setting,data.menuitems); var node=tree.zTree.getNodeByParam("mid","1"); tree.pNode=node; tree.loadNodeByPNode(); tree.zTree.expandNode(node,true); }); }, loadNodeByPNode:function(){ var parameters={ //首先加载父节点为0的树,即第一级目录 pid:tree.pNode.mid }; //这里需要先进行判断当前节点是否有子节点 if(!tree.zTree.getNodeByParam('pid',tree.pNode.mid)){ $.post("Menuitem_showMenuItemsByPid.action",parameters,function(data){ // $("#tree").zTree(tree.setting,data.menuItems); tree.zTree.addNodes(tree.pNode,data.menuitems,true); if(tree.pNode.mid==1){ var node=tree.zTree.getNodeByParam("mid","11"); tree.pNode=node; tree.loadNodeByPNode(); tree.zTree.expandNode(node,true); } }); } } }; $().ready(function(){ tree.loadRoot(); });
采用面面向对象的方法编程层次结构更加清晰,这里涉及到了向数据库发起异步请求的ajax方法以及在异步请求的情况下默认展开菜单的处理方法。
二、定时器的设计方法
普通的定时器实现方法有好多种,一开始我使用了监听器和Servlet的方法,但是实现起来都不是那么得心应手,因为需要考虑到诸如目标对象创建时间问题等等麻烦问题,最好的方式是确定目标对象一定创建完成之后再调用相关的方法。现在目标对象是RoomServiceImpl,我的需求是需要该对象纳入Spring容器管理之后调用该类中的一个初始化定时器的一个方法。很明显,最好的实现方法是使用@PostConstruct注解,该注解的作用就是当对象在Spring中创建之后自动调用一个方法。该方法的调用时间在构造方法之后。
@PostConstruct public void init() { //设置一个定时器,每天00:00的时候对房间状态进行更新 System.out.println("每天00:00进行定时更新"); Calendar calendar=Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY,24); calendar.set(Calendar.MINUTE,0); calendar.set(Calendar.SECOND, 1); Timer timer=new Timer(); timer.schedule(new TimerTask(){ @Override public void run() { //每天00:00准时刷新数据 refreshRoomState(); } }, calendar.getTime(),24*60*60*1000); }
refreshRoomState方法是最终将要定时执行的方法,该方法将使用到该对象中的某些对象属性。所以初始化对象的同时必须还要将属性值设置好,这就是spring容器的问题了。
最关键的就是该方法调用的时机和定时器的使用方法。
三、日期插件的使用。
日期插件很多,但是像样的却没有几个。这里使用了老牌的日期插件DatePicker http://www.my97.net/dp/down.asp
我的项目中的使用版本是最新的版本:https://github.com/kdyzm/HotelMembersManagement/tree/master/WebRoot/js/datePicker
使用该日期插件的好处就是能够很方便的显示时分秒
1.显示时分秒的使用方法:
<input type="text" id="d241" onfocus="WdatePicker({dateFmt:'yyyy年MM月dd日 HH时mm分ss秒'})" class="Wdate" style="width:300px"/>
2.只是有年月日的使用方法,这种方法是最常规的使用方式
<input id="d11" type="text" onClick="WdatePicker()"/>
四、DAO层和Action层代码重用
1.首先DAO的顶层接口:BaseDao
import java.io.Serializable; import java.util.Collection; public interface BaseDao<T>{ public Collection<T> getAllEntry(); public T getEntryById(Serializable id); public void saveEntry(T t); public void deleteEntry(T t); public void updateEntry(T t); }
实现该接口的顶层父类:BaseDaoImpl,所有的DAO实现类都要继承该父类
import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.util.Collection; import javax.annotation.Resource; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.transaction.annotation.Transactional; import com.kdyzm.dao.base.BaseDao; public class BaseDaoImpl<T> implements BaseDao<T>{ //泛型的真实类型 private Class<T> clazz; @Resource(name="hibernateTemplate") public HibernateTemplate hibernateTemplate; public BaseDaoImpl() { //在默认构造方法中得到真实的类型 //ParameterizedType就是泛型 ParameterizedType pt=(ParameterizedType) this.getClass().getGenericSuperclass(); this.clazz=(Class) pt.getActualTypeArguments()[0];//得到实际的参数类型,<T> // System.out.println(clazz.getSimpleName()); // System.out.println(pt.getRawType());//打印声明该方法的类或者接口类型,BaseServiceImpl } public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } @Override public Collection<T> getAllEntry() { Collection<T> collection= this.hibernateTemplate.find("from "+clazz.getName()); return collection; } @Override public T getEntryById(Serializable id) { return (T) this.hibernateTemplate.get(clazz, id); } @Override @Transactional(readOnly=false) public void saveEntry(T t) { this.hibernateTemplate.save(t); } @Override @Transactional(readOnly=false) public void deleteEntry(T t) { this.hibernateTemplate.delete(t); } @Transactional(readOnly=false) @Override public void updateEntry(T t) { this.hibernateTemplate.update(t); } }
其中最重要的就是在构造方法中的语句
public BaseDaoImpl() { //在默认构造方法中得到真实的类型 //ParameterizedType就是泛型 ParameterizedType pt=(ParameterizedType) this.getClass().getGenericSuperclass(); this.clazz=(Class) pt.getActualTypeArguments()[0];//得到实际的参数类型,<T> // System.out.println(clazz.getSimpleName()); // System.out.println(pt.getRawType());//打印声明该方法的类或者接口类型,BaseServiceImpl }
两句代码是最重要的核心代码。
2.Action同理
import java.lang.reflect.ParameterizedType; import org.apache.struts2.json.annotations.JSON; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class BaseAction<T> extends ActionSupport implements ModelDriven<T>{ private static final long serialVersionUID = -1344990340960028510L; private T t; private Class<T> clazz; //使用构造方法创建T对象 public BaseAction(){ ParameterizedType parameterizedType=(ParameterizedType) this.getClass().getGenericSuperclass(); this.clazz=(Class<T>) parameterizedType.getActualTypeArguments()[0]; System.out.println(parameterizedType.getRawType()); try { this.t=(T) this.clazz.newInstance(); } catch(Exception e){ e.printStackTrace(); } } public static final String LIST_ACTION="listAction"; public static final String ADDUI="addUI"; public static final String UPDATEUI="updateUI"; public static final String ACTIONTOACTION="actionToAction"; public static final String AJAXRESPONSE="ajaxResponse"; public String listAction=LIST_ACTION; public String addUI=ADDUI; public String updateUI=UPDATEUI; public String actionToAction=ACTIONTOACTION; public String ajaxResponse=AJAXRESPONSE; @Override @JSON(serialize=false) public T getModel() { return t; } }
五、实数的精度控制问题
使用DecimalFormat类能够很方便的实现精度控制,以精确到小数点后两位为例:
public class DecimalUtils { public static String pattern="#.00"; public static String get(double source){ DecimalFormat df=new DecimalFormat(pattern); return df.format(source); } }
六、日期处理问题
写了一个日期处理的工具类实现很方便的日期处理
package com.kdyzm.utils; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * 日期处理工具类 * @author kdyzm * */ public class DateUtils { //默认的日期格式 private static String pattern="yyyy-MM-dd HH:mm:ss"; public static void resetDefault(){ pattern="yyyy-MM-dd HH:mm:ss"; } public static void setPattern(String p){ pattern=p; } public static String getPattern(){ return pattern; } //日期格式对象转换成字符串 public static String dateToString(Date date){ SimpleDateFormat sdf=new SimpleDateFormat(pattern); String dateString=sdf.format(date); return dateString; } //字符串格式转化成日期对象 public static Date stringToDate(String dateString){ SimpleDateFormat sdf=new SimpleDateFormat(pattern); Date date=null; try { date=sdf.parse(dateString); } catch (ParseException e) { e.printStackTrace(); } return date; } //获取年月日的方法,日期格式是yyyy-MM-dd HH:mm:ss public static String getYMDByDateString(String dateString){ return dateString.split(" ")[0]; } //获取小时的方法,日期格式是yyyy-MM-dd HH:mm:ss public static String getHHByDateString(String dateString){ return dateString.split(" ")[1].split(":")[0]; } //测试工具类 public static void main(String[] args) { DateUtils.setPattern("yyyy年MM月dd日 HH时mm分ss秒"); String dateString="2015年10月8日 13时15分28秒"; Date date =new Date(); System.out.println(DateUtils.stringToDate(dateString)); System.out.println(DateUtils.dateToString(date)); } }
七、使用struts2jar包实现前端和struts2交互的问题
使用的jar包版本很有问题,版本不正确各种问题都会出现。这里使用的版本是2.1.8
必须加入三个jar包:https://github.com/kdyzm/HotelMembersManagement/tree/master/WebRoot/WEB-INF/lib/json
使用方法就是在Action中加入一个String类型的字段,并提供get和set方法
private String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; }
在前端获取该响应信息:
$.post("Json_CardAction_isCardExists.action",parameter,function(data){ if(data.message=="1"){ }else{
}
Action中所有不需要返回到前端的数据的get方法之前一定要加上@JSON(serialize=false)注解。
方法名称尽量不要使用getXXX,而要使用showXXX方法代替。
特别是接口类型的引用更应该如此。否则的话一定会报错。
八、fckEditor插件的使用问题
借用demo即可。