【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>
zTree插件使用的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即可。

  http://ckeditor.com/download

 

posted @ 2015-11-07 09:19  狂盗一枝梅  阅读(780)  评论(0编辑  收藏  举报