在本文完成下挑战书的功能,其中里面也涉及到富文本编辑器的使用
1、生成challenge数据表
在D:\medical\war\etc\db.txt文本中增加数据表challenge脚本,然后通过navicat工具把数据表在mysql中生成
/*创建挑战书记录表*/ CREATE TABLE CHALLENGE(challengeId int PRIMARY KEY NOT NULL, userId VARCHAR(20), title VARCHAR(128), depId int, prescript TEXT, challengers VARCHAR(256)) ENGINE=InnoDB DEFAULT CHARSET=UTF8
2、challenge数据表hibernate配制
在D:\medical\war\etc\mapping目录下生成challenge.hbm.xml文件,里面填写如下内容
3、定义challenge.hbm.xml对应的POJO类
package com.medical.server.dao; /** * 斗医系统发布挑战书处理类 * * @author qingkechina 2014-08-18 */ public class ChallengeDAO { /** * 挑战ID */ private int challengeId = 0; /** * 挑战人 */ private String userId = null; /** * 科室ID */ private int depId = 0; /** * 挑战标题 */ private String title = null; /** * 挑战内容 */ private String prescript = null; /** * 被挑战人 */ private String challengers = null; public int getChallengeId() { return challengeId; } public void setChallengeId(int challengeId) { this.challengeId = challengeId; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public int getDepId() { return depId; } public void setDepId(int depId) { this.depId = depId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPrescript() { return prescript; } public void setPrescript(String prescript) { this.prescript = prescript; } public String getChallengers() { return challengers; } public void setChallengers(String challengers) { this.challengers = challengers; } }
4、由于涉及到对数据表challenge数据的读取与写入操作,所以定义一个ChallengeUtil类对POJO进行操作
package com.medical.server.util; import org.hibernate.Session; import org.hibernate.Transaction; import com.medical.frame.util.FrameDBUtil; import com.medical.server.dao.ChallengeDAO; /** * 斗医系统服务端挑战书工具类 * * @author qingkechina 2014-08-18 */ public class ChallengeUtil { /** * 把挑战书记录入库 */ public static void insertChallenge(String userId, String title, int depId, String prescript, String challengers) { ChallengeDAO challengeDao = new ChallengeDAO(); challengeDao.setChallengers(challengers); challengeDao.setDepId(depId); challengeDao.setPrescript(prescript); challengeDao.setTitle(title); challengeDao.setUserId(userId); Session session = FrameDBUtil.openSession(); Transaction transaction = session.beginTransaction(); session.save(challengeDao); transaction.commit(); FrameDBUtil.closeSession(); } }
5、当用户登录系统在浏览器中发布挑战书时,需要调用到业务逻辑处理,所以定义PublishChallengeAction业务Java类,里面涉及对数据的校验
package com.medical.server.data; import com.google.gson.Gson; import com.medical.frame.FrameCache; import com.medical.frame.FrameDefaultAction; import com.medical.frame.FrameException; import com.medical.frame.bean.FramePathBean; import com.medical.frame.bean.FrameResultBean; import com.medical.frame.constant.FrameErrorCode; import com.medical.frame.util.FrameUtil; import com.medical.server.dao.UserDAO; import com.medical.server.util.ChallengeUtil; /** * 斗医系统发布挑战书处理类 * * @author qingkechina 2014-08-18 */ public class PublishChallengeAction extends FrameDefaultAction { /** * 全局Gson对象 */ private final static Gson gson = new Gson(); @Override public String execute() throws FrameException { // 用户尚未登录系统 UserDAO loginUser = FrameCache.getInstance().getUserBySession(session); if (loginUser == null) { FrameResultBean resultBean = new FrameResultBean(); resultBean.setErrorCode(FrameErrorCode.USER_NOT_LOGIN_ERROR); resultBean.setErrorDesc(FrameUtil.getErrorDescByCode(resultBean.getErrorCode())); return gson.toJson(resultBean); } // 获取挑战标题 String title = this.getParameter("title"); if (FrameUtil.isEmpty(title)) { FrameResultBean resultBean = new FrameResultBean(); resultBean.setErrorCode(FrameErrorCode.CHANLLENGE_TITLE_EMPTY); resultBean.setErrorDesc(FrameUtil.getErrorDescByCode(resultBean.getErrorCode())); return gson.toJson(resultBean); } // 获取科室ID int depId = -1; String departValue = getParameter("departId"); if (FrameUtil.isEmpty(departValue) == false) { depId = Integer.valueOf(departValue); } if (depId == -1) { FrameResultBean resultBean = new FrameResultBean(); resultBean.setErrorCode(FrameErrorCode.CHANLLENGE_DEP_EMPTY); resultBean.setErrorDesc(FrameUtil.getErrorDescByCode(resultBean.getErrorCode())); return gson.toJson(resultBean); } // 获取挑战药方内容、挑战人 String prescript = getParameter("prescript"); String challengers = getParameter("challengers"); // 写入数据库 ChallengeUtil.insertChallenge(loginUser.getUserId(), title, depId, prescript, challengers); // 设置返回路径 FramePathBean pathBean = new FramePathBean(); pathBean.setErrorCode(200); pathBean.setForwardPath("index.act?timestamp=" + System.currentTimeMillis()); return gson.toJson(pathBean); } }
6、如何调用到PublishChallengeAction业务处理类呢?我们在D:\medical\war\WEB-INF\config\challenge\challenge-data.xm定义,内容如下:
从上面的配置可以看出,当界面上触发按钮时,调用到publishChallenge的JS方法,从而触发业务逻辑。那么界面是什么样的呢?
7、在上面的这个界面原型中,药方使用纯文本描述,理论上讲只要使用textarea标签就可以了,考虑到有时还可能会上传一些中药材的图片或病情图片,所以有一个上传图片的功能,这里面就需要使用HTML的富文本编辑器了。
关于HTML富文本编辑器有很多,像百度的ueditor、Twitter的Bootstrap、Tower的Simditor等等,我们这里选择Kindeditor,为什么选择它呢?主要原因是我没有使用过,呵呵。
下面就随着我进入Kindeditor世界吧!
(1)进入http://kindeditor.net/down.php下载
(2)下载后把kindeditor解压medical应用的war\js目录下
(3)由于我们使用的是Tomcat容器,所以只保留JSP的功能即可(即删除kindeditor下的asp、asp.net和php目录)
(4)由于medical应用并非发布版本,所以不需要压缩后的js(即删除kindeditor-min.js、kindeditor-all-min.js文件)
(5)有一个examples文件夹,从名称上看应该是一个使用示例,我们可以通过这学习这个例子快速入门
完成了上述准备工作,下面就可以步入kindeditor之旅了!
8、定义challenge.html来绘制出上述界面(在D:\medical\war\module\challenge下增加challenge.html文件)
斗医
9、定义上面HTML对应的CSS样式文件(在D:\medical\war\theme\challenge下增加challenge.css文件)
/*********************************************************************/ /* 系统下战书样式 */ /*********************************************************************/ .challenge_content_wrapper{ width: 710px; margin: 20px auto; font-size: 13px; border: 1px solid #CCC; overflow: hidden; } .challenge_textarea_wrapper{ margin: 5px; padding: 8px 5px; line-height: 15px; box-shadow: 0 1px 1px rgba(0,0,0,.1) inset; border-radius: 3px; background: #FFF; border: 1px solid #ccc; color: #222; } .challenge_richtext_wrapper{ margin: 5px; padding: 0; line-height: 15px; background: #FFF; color: #222; } /*********************************************************************/ /* 下战书TextArea公共样式 */ /*********************************************************************/ .challenge_textarea_wrapper textarea{ height: 20px; line-height: 20px; width: 100%; vertical-align: bottom; /*移除滚动条*/ overflow: hidden; /*自动换行*/ word-wrap: break-word; /*移除边框*/ border: 0; background-color: #FFF; /*去除改变大小拖拽柄*/ resize: none; font-size: 13px; border-radius: 5px; } .challenge_textarea_wrapper textarea:focus{ outline: 0; outline-offset: -2px; } /*********************************************************************/ /* 药方说明样式 */ /*********************************************************************/ .challenge_text_desc{ margin: 25px 5px 0 6px; } .challenge_depart_wrapper{ margin: 5px; line-height: 15px; background-color: #FFF; color: #222; overflow: hidden; } .challenge_depart_item, .challenge_depart_item_selected{ float: left; min-width: 55px; width: auto; height: 22px; line-height: 22px; font-size: 13px; text-align: center; margin-right: 8px; background-color: #E1EAF2; border-radius: 6px; cursor: pointer; } .challenge_depart_item:hover, .challenge_depart_item_selected{ color: #FFF; background-color: #225599; } #challenge_prescript_id{ height: 80px; min-height: 80px; } .challenge_editor_switch{ float: right; width: 16px; height: 16px; /*若无属性背景图片无法显示*/ display: inline-block; background-p_w_picpath: url(../navigation/navigation.png); background-repeat: no-repeat; background-position: -80px -127px; cursor: pointer; } /*********************************************************************/ /* 文本提示信息 */ /*********************************************************************/ .challenge_hint_info{ text-align: right; margin-right: 5px; font-size: 13px; color: #999; display: none; } .challenge_hint_warn{ color: #C33; } /*********************************************************************/ /* 下战书按钮 */ /*********************************************************************/ .challenge_confirm_publish{ float: right; margin: 0 3px 10px 0; color: #FFF; font-size: 14px; line-height: 1.7; padding: 4px 10px; display: inline-block; text-align: center; background-color: #1575D5; border: 1px solid #0D6EB8; border-radius: 3px; text-shadow: 0 -1px 0 rgba(0,0,0,.5); box-shadow: 0 1px 0 rgba(255,255,255,.2) inset,0 1px 0 rgba(0,0,0,.2); }
10、为了响应界面上的动作,所以需要在D:\medical\war\js\challenge下增加challenge.js文件,该文件中有三个方法值得读者粗略地读一下,它们分别是bindEvent2Switcher、initInputComponent和publishChallenge,分别对应富文本与纯textarea切换按钮、自适应textarea高度和发布挑战书。其内容如下:
(function( window){ $(document).ready(function(){ // 生成系统菜单 generateSystemMenu(); // 选择下战书系统菜单 selectSystemMenu("system_challenge_menu"); // 获取用户简要信息 getBreifUserInfo(); // 初始化文本框 initInputComponent(); // 初始化科室类别数据 initDepartData(); // 切换开关按钮绑定事件 bindEvent2Switcher(); }); // 当前选中的科室ID var CURRENT_SELECTED_ITEM = -1; // 当前编辑器ID var CURRENT_HTML_EDITOR = null; /** * 初始化文本框 */ function initInputComponent(){ var textareaArray = new Array("challenge_title_id", "challenge_prescript_id", "challenge_challenger_id"); // 进入页面"标题textarea"获取焦点 $("#" + textareaArray[0]).focus(); $.each(textareaArray, function(i, item){ var dynamicItem = $("#" + item); // 绑定PlaceHolder bindPlaceHolder(dynamicItem); dynamicItem.bind("keyup", function(event){ // 设置textArea高度自适应 autoAdaptHeight(this); // 长度超长时给出提示信息 setLengthHint(this); }); }); } /** * textarea高度自适应 */ function autoAdaptHeight(component){ var paddingTop = parseInt($(component).css("padding-top")); var paddingBtm = parseInt($(component).css("padding-bottom")); var scrollHeight = component.scrollHeight; var height = $(component).height(); // 判断是否为chrome浏览器 if(window.navigator.userAgent.indexOf("Chrome") > 0){ if(scrollHeight - paddingTop - paddingBtm > height){ $(component).css("height", scrollHeight); } return; } $(component).css("height", scrollHeight); } /** * textarea长度超出时提示 */ function setLengthHint(component){ if(component.id == "challenge_title_id"){ if(!component.value){ return; } var titleId = $("#challenge_title_hint_id"); if(component.value && component.value.length > 96){ titleId.parent().show(); } else { titleId.parent().hide(); } titleId.text(component.value.length - 96); } } /** * 初始化科室类别数据 */ function initDepartData(){ asyncRequest("gainDepart.data", null, function(result){ var resultJson = eval(result); if(!resultJson){ return; } $("#challenge_depart_id").empty(); $.each(resultJson, function(i, item){ var departItem = $("").attr("class", "challenge_depart_item").attr("id", "challenge_depart_id_" + item.depId).text(item.depName); departItem.click(function(){ if(CURRENT_SELECTED_ITEM != -1 && CURRENT_SELECTED_ITEM != item.depId){ $("#challenge_depart_id_" + CURRENT_SELECTED_ITEM).attr("class", "challenge_depart_item"); } CURRENT_SELECTED_ITEM = item.depId; $("#challenge_depart_id_" + item.depId).attr("class", "challenge_depart_item_selected"); }); $("#challenge_depart_id").append(departItem); }); }); } /** * 切换开关按钮绑定事件 */ function bindEvent2Switcher(){ var switcher = $("#challenge_editor_switcher"); var display = switcher.attr("display"); switcher.click(function(){ var parent = $("#challenge_prescript_id").parent(); if(display === "default"){ // 设置父div样式 parent.removeClass("challenge_textarea_wrapper").addClass("challenge_richtext_wrapper"); // 设置编辑框的当前样式 display = "custom"; switcher.attr("display", "custom"); var options = {resizeType: 0, items: ["bold", "italic", "underline", "strikethrough", "|", "insertorderedlist", "insertunorderedlist", "|", "p_w_picpath"]}; CURRENT_HTML_EDITOR = KindEditor.create("#challenge_prescript_id", options); } else { // 设置父div样式 parent.removeClass("challenge_richtext_wrapper").addClass("challenge_textarea_wrapper"); // 设置编辑框的当前样式 display = "default"; switcher.attr("display", "default"); CURRENT_HTML_EDITOR = null; KindEditor.remove("#challenge_prescript_id"); } }); } /** * 发布挑战书 */ function publishChallenge(){ // 判断挑战话题 var challengeTitle = $.trim($("#challenge_title_id").val()); if(!challengeTitle){ showSystemGlobalInfo("亲,您还没有写下问题呢~~~"); return; } // 判断挑战科室 if(CURRENT_SELECTED_ITEM === -1){ showSystemGlobalInfo("亲,您还没有选择科室呢~~~"); return; } // 挑战医方内容 var challengePrescript = $.trim($("#challenge_prescript_id").val()); if(CURRENT_HTML_EDITOR){ challengePrescript = CURRENT_HTML_EDITOR.html(); } // 挑战人 var challengers = $.trim($("#challenge_challenger_id").val()); var data = {"title": challengeTitle, "departId": CURRENT_SELECTED_ITEM, "prescript": challengePrescript, "challengers": challengers}; asyncRequest("publishChallenge.data", data, function(result) { // 跳转到相应页面 var resultJson = eval(result); top.location = resultJson.forwardPath; }); } /** * 对外公开接口 */ window.publishChallenge = publishChallenge; })( window );
11、下面验证一下效果:在浏览器中输入http://localhost:8080/medical,在菜单上选择“下战书”,在下战书页面输入相应的信息后点击“发布”,如下图:
12、点击发布成功后进入系统主页面,若看到内容变化不用着急,因为这个功能尚未实现,我们查看一下数据库是否把此记录追加成功?
OK,富文本的简单应用就这样实现了,后面有机会再详细研读原码!