CMS内容管理系统
1. 简介:
内容管理系统(content management system,CMS)是一种位于WEB 前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。这里指的“内容”可能包括文件、表格、图片、数据库中的数据甚至视频等一切你想要发布到Internet、Intranet以及Extranet网站的信息。
2. 需求分析
(1) 官网中的内容或信息的显示和不显示来自于后台管理系统
(2) 开发一个后台管理系统来管理官网的信息
3. 项目架构
(1) B/S架构的项目
浏览器和服务器架构模式
(2) 前台:官网信息维护
① 文章显示
② 轮播图显示
③ 开班信息
④ 问题反馈
***文章管理-->前台代码:***
**1、分页信息展示**
(1). 使用GridManager表格插件。
document.querySelector('#table-demo-ajaxPageCode').GM({
gridManagerName: 'demo-ajaxPageCode', //表中的名称
ajaxData: '/system/article/findAll', //请求路径
ajaxType: 'POST', //请求方式
sizeData: [5,10,15,20], //每页展示的数据量
pageSize: 5, //每页展示多少数据
currentPageKey: 'localPage', //重命名页数(原名:cPage )
pageSizeKey: 'pageSize', //重命名每页数据个数(原名: pSize)
height: '100%', //高度,数据个数展示完
supportAjaxPage: true, //是否分页
//supportAdjust: false,
supportDrag: false, //列是否可移动,false不可移动
columnData: [
{
key: 'title',
align: 'center', //文本居中
text: '文章标题'
},{
key: 'type',
align: 'center',
text: '文章类型',
template: function(cell, row, index, key){
//cell :当前key对应的值(key是什么类型,cell就是什么类型)
//row :一行的信息
//index :下标
//key :key后面跟的String
return cell.name;
}
},{
key: 'url',
align: 'center',
text: 'url'
},{
key: 'clickCount',
align: 'center',
text: '点击量'
},{
key: 'content',
align: 'center',
text: '文章内容'
},{
key: 'createDate',
align: 'center',
text: '创建时间'
},{
key: 'enable',
align: 'center',
text: '是否启用',
template: function(cell, row, index, key){
return cell?"启用":"禁用";
}
},{
key: 'id',
align: 'center',
text: '操作 <a id="addById" href="javascript:;">添加</a>',
template: function(cell, row, index, key){
//row对象转换成json字符串格式
var rows = *JSON.stringify*(row);
return '<a data-id='+cell+' style="color:red" href="javascript:;">删除</a> '+
"<a data-obj='"+rows+"' style='color:blue' href='javascript:;'>修改</a>";
}
}
]
});
**2、高级查询**
(1). 使用jquery、GridManager插件
//绑定查询事件
$("#queryButton").on("click", function(){
//将表单中的信息转换成json串
var datas = $('#queryForm').serializeObject();
//将表单中的信息与localPage、pagesize分页信息一起发送至后台
GridManager.setQuery('demo-ajaxPageCode', datas);
})
**3、添加文章**
//添加,事件委托添加点击事件
$("body").on("click", "#addId", function(){
//清空隐藏域
$("#hid").val("");
//清空表单缓存
$("#saveForm")[0].reset();
// 清空富文本编辑器(百度查)
var ue = UE.getEditor('container');
$(document).ready(function () {
ue.ready(function () {
ue.setContent(''); //赋值给UEditor
});
});
//弹出模态框
$("#saveModel").modal("show")
})
**4、修改文章信息**
//修改更能,事件委托添加点击事件
$("body").on("click", "a[data-obj]", function(){
//alert("123")
//清空缓存
$("#saveForm")[0].reset();
//清空隐藏域
$("#hid").val("");
//得到当前行数据
var objs = $(this).data("obj");
//数据回显模态框
$("#saveModel").setForm(objs);
// 清空富文本编辑器(百度查)
var ue = UE.getEditor('container');
$(document).ready(function () {
ue.ready(function () {
ue.setContent(''); //赋值给UEditor
});
});
//弹出模态框
$("#saveModel").modal("show")
})
**5、修改、删除保存数据**
//保存数据。添加点击事件
$("#saveButton").on("click", function(){
//发送请求
$.ajax({
type: "post",
url: "/system/article/save",
//发送表单信息serialize(),有文件上传则不能用
data: $("#saveForm").serialize(),
//dataType: "json",
success: function(msg){
if (msg.result) {
//关闭模态框
$("#saveModel").modal("hide")
//刷新页面,true刷新后跳到第一页
GridManager.refreshGrid("demo-ajaxPageCode", true);
} else {
alert(msg.error)
}
}
})
})
**6、删除**
//删除功能,事件委托
$("body").on("click", "a[data-id]", function(){
//获取id
var id = $(this).data("id");
//弹出确认删除模态框
$("#delModal").modal("show")
//确认前,解绑点击事件
$("#delModelButton").off("")
//绑定确认事件
$("#delModelButton").on("click", function(){
//alert(id)
//发送请求
$.ajax({
type: "post",
url: "/system/article/del",
data: {"id":id},
//dataType: "json",
success: function(msg){
if (msg.result) {
//关闭模态框
$("#delModal").modal("hide")
//刷新页面
GridManager.refreshGrid("demo-ajaxPageCode", true);
} else {
alert(msg.error)
}
}
})
})
})
(3) 后台:管理系统
拥有模块:
1、文章管理
2、轮播图管理
3、开班信息
4、问题反馈
5、用户登录登出
模块功能:
***文章管理-->后台:***
**1、信息展示**
(1). 创建类BaseQuery,封装分页数据Bean
public class BaseQuery {
private Integer localPage;
private Integer pageSize;
//sql中limit分页查询中的第一个数
public Integer getBean(){
return (this.localPage - 1) * this.pageSize;
}
...
}
**2、高级查询**
(1). 新建类ArticleQuery,添加高级查询字段信息,继承BaseQuery
**3、封装后台返回数据Bean**
(1). 新建类PageBean<T>,将totals(数据总条数)与data(所有的数据)封装起来
public class BaseQuery<T> {
//数据总条数
private Integer totals = 0;
//分页数据
private List<T> data = new ArrayList<T>();
...
}
**4、封装页面数据操作结果**
(1). 新建类AjaxResult
public class AjaxResult {
//布尔类型,默认为true
private Boolean result = true;
private String error;
...
}
**5、页面静态化技术(FreeMarker)**
public class FreeMarkerUtil {
/**
* @Description:(封装FreeMarker)
* @param:@param path 默认加载路径,生成的文件存放的位置(xxx.ftl模板文件也存放在这里)
* @param:@param name 模板文件名
* @param:@param data 准备的数据(map/实体对象)
* @param:@param suffix 需要生成文件的后缀
* @param:@return
* @return:String
* @author:ly
* @date:xx
* @version:V1.0
*/
public static String createFreemarker(String path, String name, Object data, String suffix){
FileWriter out = null;
String url = null;
try {
// 1.导入freemarker.jar
// 2.获取模板(Template)对象
// 获取Configuration对象 -- 为了获取模板对象
Configuration configuration = new Configuration(Configuration.VERSION_2_3_28);
// 设置默认加载路径
File file = new File(path);
configuration.setDirectoryForTemplateLoading(file);
// 设置默认编码
configuration.setDefaultEncoding("UTF-8");
// 获取模板
Template template = configuration.getTemplate(name);
// 3.准备数据(data)
// map
// java实体对象
// 4.template.process()生成静态资源
// 按照时间轴,生成文件名+后缀的
url = System.currentTimeMillis() + suffix;
// 准备文件路径与文件名
File file2 = new File(file, url);
// 文件写出流
out = new FileWriter(file2);
// 生成静态文件
template.process(data, out);
// 返回文件名url
return url;
// 5.创建xxx.ftl模板
// 模板中使用el表达式获取数据. el表达式: ${obj}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return url;
}
}
调用FreeMarkerUtil
功能模块:轮播图管理、开班信息、问题反馈
与文章管理模块相比,轮播图管理、开班信息多加了文件上传功能
文件上传
文件上传三要素:
1、form表单的提交方式必须是post请求
2、form表单上必须要设置一个enctype="multipart/form-data"
3、input表单中必须有复杂表单项 -> type="file"
代码:
@Override
public void save(MultipartFile photo, Slide slide, HttpServletRequest req) throws Exception {
//3.1获取路径,
String realPath = req.getServletContext().getRealPath("/static/upload/");
//判断是否有文件
if (photo != null) {
//2、输入流
InputStream input = photo.getInputStream();
//3.1.1创建路径
File file = new File(realPath);
if (!file.exists()) {//文件路径不存在
//创建路径
file.mkdirs();
}
//3.2拿到文件后缀
String filename = photo.getOriginalFilename();
String suffix = filename.substring(filename.lastIndexOf("."));
//3.3时间轴生成文件名
String name = System.currentTimeMillis() + suffix;
//3.4文件写入的路径
File file2 = new File(realPath, name);
//3、输出流
FileOutputStream output = new FileOutputStream(file2);
//1、核心代码
IOUtils.copy(input, output);
//4、关流
output.close();
input.close();
//5、写入slide对象
//路径写入slide
slide.setPath("/static/upload/" + name);
//文件名写入slide
slide.setName(name);
}
//判断添加还是修改
if (slide.getId() == null) {//添加
if (photo != null) {
mapper.add(slide);
}
} else {//修改操作
Slide slideOne = mapper.findOne(slide.getId());
if (photo != null) {
//删除文件夹中原来的文件
//得到名字
String name = slideOne.getName();
File file = new File(realPath + name);
if (file.exists()) {
file.delete();
}
//执行修改
mapper.update(slide);
} else {//只修改权限
//执行修改
mapper.update(slide);
}
}
}
添加功能对应的sql语句
<!-- void add(Slide slide); 添加-->
<insert id="add">
insert into t_slide(name, path, createDate, enable)
values(#{name}, #{path}, #{createDate}, #{enable})
</insert>
修改功能对应得到sql语句
<!-- void update(Slide slide); 修改-->
<update id="update">
update t_slide set
<if test="name != null">
name=#{name},
</if>
<if test="path != null">
path=#{path},
</if>
createDate=#{createDate}, enable=#{enable} where id=#{id}
</update>
功能模块:问题反馈
与文件上传功能相比,问题反馈由前台上传,后台可添加恢复记录与删除,其余功能与实用技术相同
功能模块:用户登录登出
1、使用拦截器
2、保存登录信息使用cookie
3、登录后,刷新页面用户信息依然存在:使用session
拦截器java代码:
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object arg2) throws Exception {
//获取session
HttpSession session = req.getSession();
//获取session中的user
Object user = session.getAttribute("USER_IN_SESSION");
//判断是否有user,没有user就表示,走的其它路径,则重定向到登录路径
if (user == null) {
//重定向到登录路径
resp.sendRedirect("/system/login");
//拦截
return false;
}
//有user,则是登录路径
return true;
}
Spring-MVC.xml配置:
<!--配置拦截器组 -->
<mvc:interceptors>
<!-- 拦截器 -->
<mvc:interceptor>
<!-- 要拦截的配置,该配置必须写在不拦截的上面,/*拦截一级请求,/**拦截多级请求 -->
<mvc:mapping path="/system/**" /><!-- 只拦截后台路径 -->
<!-- 设置不拦截的配置 -->
<mvc:exclude-mapping path="/system/login"/><!-- 放行登录路径 -->
<mvc:exclude-mapping path="/system/feedback/save"/><!-- 问题反馈路径 -->
<!-- 配置拦截器 (拦截自己写的拦截器类:Interceptor.Xxx)-->
<bean class="cn.itsource.interceptor.LoginInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Cookie与Session使用,进行登录判断与保存user登录信息
1、Controller层
@RequestMapping(value="/login", method=RequestMethod.POST)
@ResponseBody
public AjaxResult login(String remember, String username, String password, HttpServletRequest req,
HttpServletResponse resp, HttpSession session){
try {
User user = service.findLogin(username, password);
//将user写入session中
session.setAttribute("USER_IN_SESSION", user);
//判断remember是否为null,为null则表示没有选中“记住我”
if (remember != null) {//选中"记住我"
//创建cookie
Cookie c1 = new Cookie("username", username);
Cookie c2 = new Cookie("password", password);
//设置生命周期
c1.setMaxAge(7*27*3600);
c2.setMaxAge(7*27*3600);
//设置路径为根路径,
c1.setPath("/");
c2.setPath("/");
//传入浏览器
resp.addCookie(c1);
resp.addCookie(c2);
} else {//没有remember,表示没有选中"记住我",则需要获取Cookie,再清除里面的数据
//获取Cookie,因为别人有可能使用Cookie传输了数据
Cookie[] cookies = req.getCookies();
//遍历
for (Cookie cookie : cookies) {
//如果getName的值为username,或者password,则清除
if ("username".equals(cookie.getName()) || "password".equals(cookie.getName())) {
//清除Cookie
cookie.setMaxAge(0);
//设置路径为根路径,清除根路径下所有的cookie
cookie.setPath("/");
//传入浏览器
resp.addCookie(cookie);
}
}
}
return new AjaxResult();
} catch (Exception e) {
e.printStackTrace();
//e.getMessage()打印返回的错误信息
return new AjaxResult(false, e.getMessage());
}
}
2、Service层
@Override
public User findLogin(String username, String password) throws Exception {
//查到一条user
User user = mapper.findByName(username);
//判断是否查到
if (user == null) {
//自定义异常信息
throw new Exception("用户不存在");
} else{
//判断密码是否相等
if (password.equals(user.getPassword())) {
return user;
} else {
//自定义异常信息
throw new Exception("密码错误");
}
}
}
4. 技术选型
(1) 开发工具:idea
(2) 数据库:Mysql
(3) 后端框架:SSM
(4) 前端框架:jQuery(使用$)、Bootstrap(模态框)、GridManager表格插件
①. jstl(页面取值<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>) + el(后台传值Map<String, Object> map, 页面取值${ })【同步】
②. jquery拼接【异步】(ajax)
③. gridManager【异步】