【斗医】【16】Web应用开发50天
在本文完成下挑战书的功能,其中里面也涉及到富文本编辑器的使用
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文件,里面填写如下内容
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.medical.server.dao">
<class name="ChallengeDAO" table="CHALLENGE">
<id name="challengeId" column="challengeId" type="int">
<generator class="increment"></generator>
</id>
<property name="userId" column="userId" />
<property name="depId" column="depId" />
<property name="title" column="title" />
<property name="prescript" column="prescript" />
<property name="challengers" column="challengers" />
</class>
</hibernate-mapping>
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定义,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<business-config>
<!--发布挑战书-->
<business name="publishChallenge" business-class="com.medical.server.data.PublishChallengeAction" />
</business-config>
从上面的配置可以看出,当界面上触发按钮时,调用到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文件)
<!DOCTYPE HTML>
<html>
<head>
<title>斗医</title>
<!--利于搜索引擎查询-->
<meta name="description" content="斗医是一个医学交流平台" />
<meta name="keywords" content="医学,交流,讨论" />
<!--设置字符集-->
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<!--页面不缓存-->
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="cache-control" content="no-cache,must-revalidate" />
<meta http-equiv="expires" content="Wed, 26 Feb 1997 08:21:57 GMT" />
<!--引入外部文件-->
<link rel="stylesheet" type="text/css" href="theme/navigation/navigation.css">
<link rel="stylesheet" type="text/css" href="theme/challenge/challenge.css">
<script src="js/common/jquery.js"></script>
<script src="js/kindeditor/kindeditor-all.js"></script>
<script src="js/common/common.js"></script>
<script src="js/challenge/challenge.js"></script>
</head>
<body>
<!--系统导航菜单-->
<div id="system_navigation_menu"></div>
<!--系统内容部分-->
<div class="system_content">
<div class="challenge_content_wrapper">
<div class="challenge_textarea_wrapper">
<textarea id="challenge_title_id" placeholder="写下您的问题"></textarea>
</div>
<div class="challenge_hint_info">
已超出<label class="challenge_hint_warn" id="challenge_title_hint_id"></label>字
</div>
<div class="challenge_text_desc">选择所属科室(必填):</div>
<div class="challenge_depart_wrapper" id="challenge_depart_id"></div>
<div class="challenge_text_desc">
药方说明(可选):
<span class="challenge_editor_switch" id="challenge_editor_switcher" display="default"></span>
</div>
<div class="challenge_textarea_wrapper">
<textarea id="challenge_prescript_id" placeholder="写下病人神、色、形、态、舌象等症状......"></textarea>
</div>
<div class="challenge_hint_info">
已超出<label class="challenge_hint_warn" id="challenge_prescript_hint_id"></label>字
</div>
<div class="challenge_text_desc">挑战人(可选):</div>
<div class="challenge_textarea_wrapper">
<textarea id="challenge_challenger_id" placeholder="选择您的挑战人"></textarea>
</div>
<div class="challenge_text_desc">
<a href="javascript:publishChallenge()" class="challenge_confirm_publish">发布</a>
</div>
</div>
</div>
</body>
</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-image: 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 = $("<div />").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", "|", "image"]};
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,富文本的简单应用就这样实现了,后面有机会再详细研读原码!
本文出自 “青客” 博客,请务必保留此出处http://qingkechina.blog.51cto.com/5552198/1541813
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。