【斗医】【16】Web应用开发20天

时间:2021-10-12 18:02:47

    在本文完成下挑战书的功能,其中里面也涉及到富文本编辑器的使用

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方法,从而触发业务逻辑。那么界面是什么样的呢?

【斗医】【16】Web应用开发20天


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,在菜单上选择“下战书”,在下战书页面输入相应的信息后点击“发布”,如下图:

【斗医】【16】Web应用开发20天12、点击发布成功后进入系统主页面,若看到内容变化不用着急,因为这个功能尚未实现,我们查看一下数据库是否把此记录追加成功?

【斗医】【16】Web应用开发20天

OK,富文本的简单应用就这样实现了,后面有机会再详细研读原码!





本文出自 “青客” 博客,请务必保留此出处http://qingkechina.blog.51cto.com/5552198/1541813