CMS:内容管理系统

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: '操作&ensp;<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>&ensp;'+
			                    "<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【异步】
  • 9
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值