最近项目需要做一个会议日程安排的功能,通过日历控件查询日程安排。找到了dhtmlxScheduler这个控件,java下的官方网站http://javaplanner.com/docs/index.html ,最终效果是这样的:
由于网上关于这个控件的中文资料比较少,分享自己经验供同样需求的人使用。
项目框架是spring MVC + hibernate,使用此控件方法如下:
首先是准备工作,下载并导入各种相关的包:
dhtmlxScheduler library files (控件的js/css文件);
javaplanner.jar file (you can download it here).
然后,处理需要在控件中显示的日程,分为两部分:建立表结构和定义对应实体类。日程bean(即上图表示Event的类,在我的项目中是会议Meeting类)继承DHXEvent类,日程类会继承DHXEvent类中的四个变量,分别是id,start_date,end_date,text,id为整型。
Meeting.java import java.util.Date; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.PrePersist; import javax.persistence.PreUpdate; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.validation.constraints.NotNull; import org.apache.commons.lang3.StringUtils; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hibernate.annotations.DynamicInsert; import org.hibernate.annotations.DynamicUpdate; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; import org.hibernate.search.annotations.Analyze; import org.hibernate.search.annotations.DateBridge; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Index; import org.hibernate.search.annotations.Resolution; import org.hibernate.search.annotations.Store; import org.hibernate.validator.constraints.Length; import com.dhtmlx.planner.DHXEvent; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.thinkgem.jeesite.common.persistence.DataEntity; import com.thinkgem.jeesite.modules.sys.entity.User; import com.thinkgem.jeesite.modules.sys.utils.UserUtils; /** * @author MuQiong * Class Description * 会议实体 */ @Entity @Table(name = "oa_meeting") @DynamicInsert @DynamicUpdate @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class Meeting extends DHXEvent { private static final long serialVersionUID = 1L; private User user;//创建用户 private Room room;//会议房间 //private String text;//会议主题 private String description;//会议描述 private String status;//处理状态 private String location;//和平里or二基地 private String opinion;//审批意见 private int attendance;//参会人数 private User createBy; // 创建者 private Date createDate;// 创建日期 private User updateBy; // 更新者 private Date updateDate;// 更新日期 private String delFlag; // 删除标记(0:正常;1:删除;2:审核) public Meeting(){ super(); this.delFlag = DataEntity.DEL_FLAG_NORMAL; } public Meeting(int id){ this(); this.id = id; this.delFlag = DataEntity.DEL_FLAG_NORMAL; } public Meeting(int id, User user, Room room){ this(id); this.user = user; this.room = room; this.delFlag = DataEntity.DEL_FLAG_NORMAL; } @PrePersist public void prePersist(){ User user = UserUtils.getUser(); if (StringUtils.isNotBlank(user.getId())){ this.updateBy = user; this.createBy = user; } this.updateDate = new Date(); this.createDate = this.updateDate; } @PreUpdate public void preUpdate(){ User user = UserUtils.getUser(); if (StringUtils.isNotBlank(user.getId())){ this.updateBy = user; } this.updateDate = new Date(); } public void setId(int id){ this.id = id; } @Id @GenericGenerator(name = "idGenerator", strategy = "increment") @GeneratedValue(generator = "idGenerator") public Integer getId(){ return id; } public void setUser(User user){ this.user = user; } @ManyToOne @JoinColumn(name="user_id") @NotFound(action = NotFoundAction.IGNORE) @NotNull public User getUser(){ return user; } public void setRoom(Room room){ this.room = room; } @ManyToOne @JoinColumn(name="room_id") @NotFound(action = NotFoundAction.IGNORE) @NotNull public Room getRoom(){ return room; } public void setStartDate(Date startDate){ this.start_date = startDate; } @Temporal(TemporalType.TIMESTAMP) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") public Date getStartDate(){ return start_date; } public void setEndDate(Date endDate){ this.end_date = endDate; } @Temporal(TemporalType.TIMESTAMP) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") public Date getEndDate(){ return end_date; } public void setTitle(String title){ this.text = title; } @Column(name = "text") public String getTitle(){ return text; } public void setDescription(String description){ this.description = description; } public String getDescription(){ return description; } public void setStatus(String status){ this.status = status; } public String getStatus(){ return status; } public void setLocation(String location){ this.location = location; } public String getLocation(){ return location; } public void setOpinion(String opinion){ this.opinion = opinion; } public String getOpinion(){ return opinion; } public void setAttendance(int attendance){ this.attendance = attendance; } public int getAttendance(){ return this.attendance; } @JsonIgnore @ManyToOne(fetch=FetchType.LAZY) @NotFound(action = NotFoundAction.IGNORE) public User getCreateBy() { return createBy; } public void setCreateBy(User createBy) { this.createBy = createBy; } @Temporal(TemporalType.TIMESTAMP) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } @JsonIgnore @ManyToOne(fetch=FetchType.LAZY) @NotFound(action = NotFoundAction.IGNORE) public User getUpdateBy() { return updateBy; } public void setUpdateBy(User updateBy) { this.updateBy = updateBy; } @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES) @DateBridge(resolution = Resolution.DAY) public Date getUpdateDate() { return updateDate; } public void setUpdateDate(Date updateDate) { this.updateDate = updateDate; } @Length(min=1, max=1) @Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES) public String getDelFlag() { return delFlag; } public void setDelFlag(String delFlag) { this.delFlag = delFlag; } }
数据库用的mySQL:
CREATE TABLE oa_meeting ( id int(64) NOT NULL COMMENT '编号', user_id varchar(64) NOT NULL COMMENT '创建用户编号', room_id varchar(64) NOT NULL COMMENT '会议房间编号', start_date datetime COMMENT '开始时间', end_date datetime COMMENT '结束时间', text varchar(64) COMMENT '会议主题', description varchar(64) COMMENT '会议描述', status varchar(64) COMMENT '处理状态', location varchar(64) COMMENT '会议室区域', opinion varchar(64) COMMENT '审批意见', attendance int(32) COMMENT '参会人数', create_by varchar(64) COMMENT '创建者', create_date datetime COMMENT '创建时间', update_by varchar(64) COMMENT '更新者', update_date datetime COMMENT '更新时间', del_flag char(1) DEFAULT '0' NOT NULL COMMENT '删除标记', PRIMARY KEY (id) ) COMMENT = '会议室预订表';
下一步,利用hibernate连接数据库,hibernate配置文件和hibernateUtils类如下:
hibernate.cfg.xml<!--省略了需要的mapping class这个根据自己需要处理的实体添上就可以了--> <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="cache.use_second_level_cache">false</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/jeesite</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.pool_size">1</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="current_session_context_class">thread</property> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="use_sql_comments">true</property> <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <property name="hibernate.c3p0.max_size">20</property> <property name="hibernate.c3p0.min_size">5</property> <property name="automaticTestTable">Test</property> <property name="hibernate.c3p0.max_statements">100</property> <property name="hibernate.c3p0.idle_test_period">120</property> <property name="hibernate.c3p0.acquire_increment">1</property> <property name="c3p0.testConnectionOnCheckout">true</property> <property name="c3p0.idleConnectionTestPeriod">18000</property> <property name="c3p0.maxIdleTime">25000</property> <mapping class="…… …… …… <!-- <mapping class="com.thinkgem.jeesite.modules.*" />--> <!-- <mapping class="com.thinkgem.jeesite" file="" jar="" package="hibernate.cfg.xml" resource="Event.hbm.xml" /> --> </session-factory> </hibernate-configuration>
HibernateUtil.java import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.ImprovedNamingStrategy; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; /** * @author MuQiong * @version 2014-9-4 上午11:26:52 * hibernate 工具类 for日历查询 */ public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { Configuration cfg = new Configuration().setNamingStrategy( ImprovedNamingStrategy.INSTANCE).configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() .applySettings(cfg.getProperties()).buildServiceRegistry(); return cfg.buildSessionFactory(serviceRegistry); } catch (Throwable e) { throw new ExceptionInInitializerError(e); } } private HibernateUtil() { } public static SessionFactory getSessionFactory() { return sessionFactory; } }
下一步,写一个service类继承DHXEventsManager类,该类负责利用HibernateUtil实现对实体的CRUD功能,这里暂时只完成了读取数据即getEvents方法。
MeetingEventsManager.java /** * @author MuQiong * 日历查询会议室预定情况service */ @Service @Transactional(readOnly = true) public class MeetingEventsManager extends DHXEventsManager { public MeetingEventsManager(HttpServletRequest request) { super(request); } @Override public Iterable getEvents() { Session session = HibernateUtil.getSessionFactory().openSession(); List<Meeting> evs = new ArrayList<Meeting>(); try { // session.clear(); Criteria criteria = session.createCriteria(Meeting.class); evs = criteria/*.setCacheMode(CacheMode.IGNORE)*/.list(); // System.out.println(evs.size()); } catch (RuntimeException e) { e.printStackTrace(); } finally { session.flush(); session.close(); } return evs; } @Override @Transactional(readOnly = false) public DHXStatus saveEvent(DHXEv event, DHXStatus status) { Session session = HibernateUtil.getSessionFactory().openSession(); try { session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); if (status == DHXStatus.UPDATE) session.update(event); else if (status == DHXStatus.DELETE) session.delete(event); else if (status == DHXStatus.INSERT) session.save(event); session.getTransaction().commit(); } catch (RuntimeException e) { e.printStackTrace(); } finally { session.flush(); session.close(); } return status; } @Override @Transactional(readOnly = false) public DHXEv createEvent(String id, DHXStatus status) { return new DHXEvent(); } }
后台的最后一步也是关键一步,spring的controller类,许多关于控件界面的设置都是在这里完成的,比如说,你可以这样s.calendars.attachMiniCalendar();添加选择日期控件,更多设置请参见http://javaplanner.com/docs/index.html :
QueryController.java /** * @author MuQiong * 日历查询controller */ @Controller @RequestMapping(value = "${adminPath}/oa/query") public class QueryController { /* * @Autowired private CustomEventsManager customEventsManager; */ @RequestMapping(value = {"list", "/"}) public ModelAndView scheduler(HttpServletRequest request) throws Exception { DHXPlanner s = new DHXPlanner("/jeesite/static/dhtmlxScheduler/", DHXSkin.TERRACE); s.config.setScrollHour(8); s.setWidth(900); s.config.setTimeStep(60); s.config.setFirstHour(8); s.config.setLastHour(19); s.config.setLimitTimeSelect(true); // clear default lightbox fields s.lightbox.clear(); // contact details field DHXLightboxText title = new DHXLightboxText("text", "会议主题"); title.setFocus(true); title.setHeight(40); s.lightbox.add(title); // time field DHXLightboxTime time = new DHXLightboxTime("time", "时长"); s.lightbox.add(time); s.load("meetings", DHXDataFormat.JSON); s.data.dataprocessor.setURL("meetings"); ModelAndView mnv = new ModelAndView("modules/oa/queryList"); mnv.addObject("body", s.render()); return mnv; } @RequestMapping("/meetings") @ResponseBody public String meetings(HttpServletRequest request) { MeetingEventsManager evs = new MeetingEventsManager(request); return evs.run(); } }
最后就是前端页面jsp文件了
queryList.jsp <%@ page contentType="text/html;charset=UTF-8" %> <%@ include file="/WEB-INF/views/include/taglib.jsp"%> <html> <body> <div class="content" id="content"> <div class="scheduler" id="scheduler">${body}</div> </div> </body> </html>
以上就完成简单的基本功能了。
如果有什么问题,希望指出。