最近前端菜鸟的我跟着做了一个项目,主要负责后台管理模块中的新闻管理模块,主要功能有新闻的增删改查,主要涉及到的一些控件有:自动填充的form表单,二级联动下拉框和富文本编辑器,接下来就把这次项目学习到的知识记录下来,算是复习一下,也方便以后有类似需求的同学借鉴。
首先,我们这次使用的框架是jeeplus,虽然它的评价都不是很好,说它丑,还花钱,并且还是抄袭jeesite只是扒个皮,但其实在项目里我觉得使用起来还是挺方便的,而且也不算丑,大家可以自行到官网查看API和使用说明等文档,需要说明的是,他确实是一个比较不错的应用框架,对二次开发来说很方便,使用代码生成器可以为我们自动生成一些基本代码,避免了在开发过程中一些重复性的工作。下边是官网地址:http://www.jeeplus.org/ 具体的配置和环境搭建就不说了,API上都写的很清楚,接下来介绍使用jeeplus自动生成代码并加载到自己的项目中。
点击代码生成中的表单配置,添加一个表单
上图定义了一个名为news_test的表单,数据库表名为news_test,对应的的实体类javaBean或者说与数据库表对应的实体类的类名为NewsTest,实体类的说明为测试新闻管理entity,该表是一个单表,也就是独立存在的表,没有外键,也不存在父表或者子表,只是为了存放新闻发布的相关信息。
接下来,在数据库属性分页中,添加了如上的属性,这里要注意的是文章内容是想通过富文本在线编辑,而不是使用附件上传这种,所以它的类型一定要注意,设置成longblob,这张表主要是为了设置数据库表的,数据库会自动创建news_test表,并且添加以上的字段,并且对应的说明和类型等都会设置好。也注意这里,我把fbsj字段设置成varchar类型,而没有设置成时间类型(比如date,dateTime等),原因是我为了接下来更方便的操作时间显示的格式,我想通过前台传回一个字符串,而不是一个时间对象,因为js时间对象的格式和我们习惯的时间格式不同。接下来是页面属性分页的配置
这个分页是对实体类的定义,以及sql语句的xml文件的基本配置,java属性名称对应的就是实体类当中的属性,表单栏是确定是否显示在弹出框中,我在这里是想在弹出框中加载富文本编辑器,而对应的发布时间是不想由用户填写的,是前台添加事件,当表单提交时,触发事件,获得当前时间,然后赋值到fbsj框里,传输到后台。列表栏是指是否显示在列表里,这里其实就是新闻列表,查询栏对应的是查询条件,我这里是select from...where bk_id=...AND lm_id=...通过查找不同的栏目来显示在该栏目里的新闻。注意,这里的content的显示表单类型要设置成富文本编辑器,这样前台代码中,对应content的div才会是他默认的富文本编辑器样式。我这里没有使用自定义java对象,所以第三个分页没有操作,这里也就不向大家介绍了,大家如果需要可以自己查看API。接下来就是点击确认,注意,点击确认后,需要同步数据库,这样才能在数据库中建立相应的表进行配置。同步完成之后,我们就可以使用代码自动生成这个功能了,把代码检出。一般都是在D盘中新增了一个src文件。目录结构如下:
src
--main
----java
------com--jeeplus--modules--news_test(dao、entity、service、web)
----resources
------mapping--modules--news_test
--webcontent
----webpage--modules--news_test
其中java文件夹中包括了后台的代码,dao对应数据库操作接口,entity对应实体类,service对应业务逻辑接口,web对应控制层,resources文件夹里主要存放的是sql语句的xml文件,主要是把实体和数据库之间建立映射,采用了mybatis数据持久层。而webcontent就是存放的前台代码。接下来要做的就是把文件加载到我们的项目里了。就是把三个news_test文件夹分别复制到我们项目中对应的文件夹下边就可以了。
最终项目目录结构如下:
数据库中也已经存在news_test表,表结构如下:
我们代码已经没有问题了,初步的代码都已经有了,接下来我们可以测试一下。在jeeplus管理中,点击代码生成下的表单配置,找到我们刚才创建的news_test表,勾选上之后,点击上边的生成菜单,弹出菜单配置窗口,如下配置:
点击确定后,刷新界面就可以看到新闻管理这个菜单了,注意,如果打开该菜单,提示用户权限不足,只需要重新启动一下项目就可以了,因为菜单栏其实也对应着后台相应的文件,此时虽然把前台界面刷新了,只是操作的前台界面文件,并没有在后台文件中生成相应的记录,所以会提示用户权限不足,重启后刷新页面,可以看到如下界面:
这里对该表的增删改查,jeeplus其实也经帮我们自动生成了,我们可以测试一下新增一条新闻信息,然后删除,修改等。mmp,我前边忽略了一个问题,因为我的bk_id和lm_id是想做成下拉框,在数据库中写死,前台只需要读取数据库中的记录显示出来就可以了,而不是用户自定义这两项,所以把前边页面属性配置那里,bk_id和lm_id对应的显示表单类型修改成下拉框。。。。。在修改完成之后,需要重新生成代码,然后把代码加到项目里来,当然,其实手动自己改还是更方便的,之前无非就是错把select标签写成了input标签,只要在前台页面代码中自己动手改一下就好了。
好,前边其实都是一些简单的图形化操作,接下来就要根据我们的实际需求来进行二次开发了,首先我们这个二级联动下拉框应该如何实现呢?我的思路是这样,因为怕中文数据在传输过程中太复杂,所以我想通过id来进行传输,在数据库中读取相应的中文名称。首先建立两张表板块表和栏目标,板块表存储bk_id和对应的板块名称,栏目表里存放lm_id和栏目名称。在数据库中建立如下两张表,news_bk,news_lm,如下:
板块:
填入初始值,我设置成3个板块a,b,c,如下:
栏目:
填入初始值,每个版块下边还有2个模块:
当然,创建完数据表以后一定需要创建对应的实体对象了,在项目entity文件夹中创建如下两个java文件,代码如下:
/** * 新闻板块Entity * @author jts * @version 2017-08-13 */ public class NewsBk extends DataEntity<NewsBk> { private static final long serialVersionUID = 1L; private String bk_id; // 板块id private String bk_name; //板块名称 public NewsBk() { super(); } public NewsBk(String bk_id){ super(bk_id); } @Length(min=1, max=64, message="板块id长度必须介于 1 和 64 之间") @ExcelField(title="板块id", align=2, sort=1) public String getBk_id() { return bk_id; } public void setBk_id(String bk_id) { this.bk_id = bk_id; } @Length(min=1, max=64, message="板块名称长度必须介于 1 和 64 之间") @ExcelField(title="板块名称", align=2, sort=2) public String getBk_name() { return bk_name; } public void setBk_name(String bk_name) { this.bk_name = bk_name; } }
/** * Copyright © 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved. */ package com.jeeplus.modules.news_test.entity; import org.hibernate.validator.constraints.Length; import com.jeeplus.common.persistence.DataEntity; import com.jeeplus.common.utils.excel.annotation.ExcelField; /** * 新闻栏目Entity * @author jts * @version 2017-08-13 */ public class NewsLm extends DataEntity<NewsLm> { private static final long serialVersionUID = 1L; private String lm_id; // 栏目id private String bk_id; //板块id private String lm_name; //栏目名称 public NewsLm() { super(); } public NewsLm(String lm_id){ super(lm_id); } @Length(min=1, max=64, message="栏目id长度必须介于 1 和 64 之间") @ExcelField(title="栏目id", align=2, sort=1) public String getLm_id() { return lm_id; } public void setLm_id(String lm_id) { this.lm_id = lm_id; } @Length(min=1, max=64, message="板块id长度必须介于 1 和 64 之间") @ExcelField(title="板块id", align=2, sort=2) public String getBk_id() { return bk_id; } public void setBk_id(String bk_id) { this.bk_id = bk_id; } @Length(min=1, max=64, message="栏目名称长度必须介于 1 和 64 之间") @ExcelField(title="栏目名称", align=2, sort=3) public String getLm_name() { return lm_name; } public void setLm_name(String lm_name) { this.lm_name = lm_name; } }
这时,我们打开的界面如下:
其中,前两个下拉框点击时,什么内容都没有,只有空,这就证明我们还没有把后台数据库中的值传入进来,所以接下来看前台代码,前台代码主要有两个文件,一个是List对应的是新闻展示列表界面,另一个是Form,对应的就是弹出的窗口界面,也就是上图所展示的界面,我们先从List界面修改。List界面代码如下:
<%@ page contentType="text/html;charset=UTF-8" %> <%@ include file="/webpage/include/taglib.jsp"%> <html> <head> <title>新闻管理</title> <meta name="decorator" content="default"/> <script type="text/javascript"> $(document).ready(function() { }); </script> </head> <body class="gray-bg"> <div class="wrapper wrapper-content"> <div class="ibox"> <div class="ibox-title"> <h5>新闻管理列表 </h5> <div class="ibox-tools"> <a class="collapse-link"> <i class="fa fa-chevron-up"></i> </a> <a class="dropdown-toggle" data-toggle="dropdown" href="#"> <i class="fa fa-wrench"></i> </a> <ul class="dropdown-menu dropdown-user"> <li><a href="#">选项1</a> </li> <li><a href="#">选项2</a> </li> </ul> <a class="close-link"> <i class="fa fa-times"></i> </a> </div> </div> <div class="ibox-content"> <sys:message content="${message}"/> <!--查询条件--> <div class="row"> <div class="col-sm-12"> <form:form id="searchForm" modelAttribute="newsTest" action="${ctx}/news_test/newsTest/" method="post" class="form-inline"> <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}"/> <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}"/> <table:sortColumn id="orderBy" name="orderBy" value="${page.orderBy}" callback="sortOrRefresh();"/><!-- 支持排序 -->
<div class="form-group"> <span>板块id:</span> <form:select path="bk_id" class="form-control m-b"> <form:option value="" label=""/> <form:options items="${fns:getDictList('')}" itemLabel="label" itemValue="value" htmlEscape="false"/> </form:select> <span>栏目id:</span> <form:select path="lm_id" class="form-control m-b"> <form:option value="" label=""/> <form:options items="${fns:getDictList('')}" itemLabel="label" itemValue="value" htmlEscape="false"/> </form:select> </div>
</form:form> <br/> </div> </div> <!-- 工具栏 --> <div class="row"> <div class="col-sm-12"> <div class="pull-left"> <shiro:hasPermission name="news_test:newsTest:add"> <table:addRow url="${ctx}/news_test/newsTest/form" title="新闻管理"></table:addRow><!-- 增加按钮 --> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:edit"> <table:editRow url="${ctx}/news_test/newsTest/form" title="新闻管理" id="contentTable"></table:editRow><!-- 编辑按钮 --> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:del"> <table:delRow url="${ctx}/news_test/newsTest/deleteAll" id="contentTable"></table:delRow><!-- 删除按钮 --> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:import"> <table:importExcel url="${ctx}/news_test/newsTest/import"></table:importExcel><!-- 导入按钮 --> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:export"> <table:exportExcel url="${ctx}/news_test/newsTest/export"></table:exportExcel><!-- 导出按钮 --> </shiro:hasPermission> <button class="btn btn-white btn-sm " data-toggle="tooltip" data-placement="left" onclick="sortOrRefresh()" title="刷新"><i class="glyphicon glyphicon-repeat"></i> 刷新</button> </div> <div class="pull-right"> <button class="btn btn-primary btn-rounded btn-outline btn-sm " onclick="search()" ><i class="fa fa-search"></i> 查询</button> <button class="btn btn-primary btn-rounded btn-outline btn-sm " onclick="reset()" ><i class="fa fa-refresh"></i> 重置</button> </div> </div> </div> <!-- 表格 --> <table id="contentTable" class="table table-striped table-bordered table-hover table-condensed dataTables-example dataTable"> <thead> <tr> <th> <input type="checkbox" class="i-checks"></th> <th class="sort-column bk_id">板块id</th> <th class="sort-column lm_id">栏目id</th> <th class="sort-column title">标题</th> <th class="sort-column content">内容</th> <th class="sort-column fbsj">fbsj</th> <th>操作</th> </tr> </thead> <tbody> <c:forEach items="${page.list}" var="newsTest"> <tr> <td> <input type="checkbox" id="${newsTest.id}" class="i-checks"></td> <td><a href="#" onclick="openDialogView('查看新闻管理', '${ctx}/news_test/newsTest/form?id=${newsTest.id}','800px', '500px')"> ${newsTest.bk_id} </a></td> <td> ${newsTest.lm_id} </td> <td> ${newsTest.title} </td> <td> ${fns:unescapeHtml(newsTest.content)} </td> <td> ${newsTest.fbsj} </td> <td> <shiro:hasPermission name="news_test:newsTest:view"> <a href="#" onclick="openDialogView('查看新闻管理', '${ctx}/news_test/newsTest/form?id=${newsTest.id}','800px', '500px')" class="btn btn-info btn-xs" ><i class="fa fa-search-plus"></i> 查看</a> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:edit"> <a href="#" onclick="openDialog('修改新闻管理', '${ctx}/news_test/newsTest/form?id=${newsTest.id}','800px', '500px')" class="btn btn-success btn-xs" ><i class="fa fa-edit"></i> 修改</a> </shiro:hasPermission> <shiro:hasPermission name="news_test:newsTest:del"> <a href="${ctx}/news_test/newsTest/delete?id=${newsTest.id}" onclick="return confirmx('确认要删除该新闻管理吗?', this.href)" class="btn btn-danger btn-xs"><i class="fa fa-trash"></i> 删除</a> </shiro:hasPermission> </td> </tr> </c:forEach> </tbody> </table> <!-- 分页代码 --> <table:page page="${page}"></table:page> <br/> <br/> </div> </div> </div> </body> </html>
可以看出这里是使用了自动填充表单来获取数据,并且填充到相应的容器中。