CMS项目小结

0 篇文章 0 订阅

CMS项目总结

什么是CMS

内容管理系统(content management system,CMS)是一种位于WEB 前端(Web 服务器)和后端办公系统或流程(内容创作、编辑)之间的软件系统。内容的创作人员、编辑人员、发布人员使用内容管理系统来提交、修改、审批、发布内容。这里指的“内容”可能包括文件、表格、图片、数据库中的数据甚至视频等一切你想要发布到Internet、Intranet以及Extranet网站的信息。

项目实现的功能

1.高级查询对数据的增删改查
2.添加,删除和更新操作时生成静态页面
3.浏览次数或点击次数的实现
4.轮播图的列表显示和高级查询
5.文件上传功能
①Post请求
②enctype=“multipart/form-data”
③type=“file”
6.登录功能
7.注销功能
8.登录功能的点击记住我功能
9.取消记住我
10.登录拦截

项目实现使用的技术和知识点

1.项目整体使用Maven结构的样式
2.框架使用集成ssm
3.FreeMark
4.JS代码
5.富文本编辑器
6.模态框的使用
7.Cookie和Session
8.SVN

Spring入门
1.导入所需要的jar包
	core
	context
	beans
	expression
	依赖包:logging
2.Spring的配置文件【菜单】
	1.在资源文件resources中新建一个xml文件【applicationContext.xml】
	2.拷贝文档中的申明和约束
3.创建类Tomato,自定义业务方法
4.配置Bean,注册Bean【在菜单上写上菜名 ,并为菜名指定唯一标识,方便获取】
	<!-- 
Spring中管理的对象称之为bean ,
class="创建对象所属类的完全限定名",
id是区分容器中对象的唯一标识,方便获取,也可以是name属性

–>

5.Spring容器的实例化【创建管家】
BeanFactory【过时】
//第一种方式:
//读取类路径 ClassPath下的资源文件applicationContext.xml
ClassPathResource resource = new ClassPathResource(“applicationContext.xml”);
//将资源文件交给BeanFactory去创建容器对象
BeanFactory factory = new XmlBeanFactory(resource);//管家 ,并将配置文件交给管家 //接口
ApplicationContext【常用】
//第二种方式://接口ApplicationContext extends BeanFactory – ApplicationContext功能要多一些
ApplicationContext ac = new ClassPathXmlApplicationContext(“applicationContext.xml”);
注意:管家是需要new出来的
6.获取Bean对象,使用该对象
方式一:Tomato t = factory.getBean(“tomato”,Tomato.class);
方式二:Tomato t = (Tomato)ac.getBean(“tomato”);
解释:根据配置文件中的id值去获取对象,返回是一个Object需要强转
目的:获取一个Tomato对象
1.类Tomato 2.管家 3.菜单 4.菜单上写上菜名 5. 把菜单交给他
BeanFactory和ApplicationContext区别和联系
联系:ApplicationContext接口继承自BeanFactory,拥有更多的功能
区别:
ApplicationContext
默认是在创建容器的时候就创建了对象【迫切加载】
想办法将迫切加载转成延迟加载
lazy-init=“true”
配置单个bean懒加载
default-lazy-init=“true”
配置所有bean懒加载
BeanFactory
默认是在获取的时候才创建对象【延迟加载/懒加载】
Spring配置细节
配置Bean的作用域
单例 = singleton
默认状态【绝大多数】
多例 = 原型 = prototype
scope=“prototype”
测试步骤:
1.先测试默认状态 – 单例
2.写上配置scope=“prototype” 再测试是否是多例的
@Autowired
private MyBean mybean1;
@Autowired
private MyBean mybean2;

@Test
public void testBean(){
System.out.println(mybean1 == mybean2);//true – false
}
配置懒加载
BeanFactory默认是懒加载【延迟加载】的
ApplicationContext默认是迫切加载
lazy-init=“true”
配置单个懒加载
default=lazy-init=“true”
配置所有对象懒加载
Spring中的Bean的生命周期
生命周期:就是对象从创建到销毁的一个过程
Spring中Bean的生命周期:Spring中管理的对象从创建到销毁的一个过程
实例化和初始化
实质是Spring容器帮我们调用了无参构造【创建对象】和指定的初始化方法【一般做初始化工作】
如果Spring容器是BeanFactory,在对象使用的时候调用【懒加载】
如果Spring容器是ApplicationContext,默认在创建容器的时候调用【迫切加载】
单例才是
多例不是,多例的对象还是懒加载
因为它不知道创建多少个对象
只有在获取的时候才知道你需要多少个对象
销毁
实质上也是Spring容器去调用指定销毁方法,但是仅仅是的调用了这个方法,并没有销毁这个对象,可以在销毁方法中做一些销毁和清理工作【释放资源,关流,关闭连接】
这个销毁方法一般是在容器关闭的时候调用,但是在Springtest中用完之后会自动关闭容器,就会自动调用销毁方法
一般情况下初始化和销毁不用管,框架中会自动进行管理

Day1

功能:跳转到后台首页【WEB-INF/view/index.jsp】

1.导入后台首页页面
	将课件resources中的views文件夹复制到WEB-INF中
2.导入静态资源
	在根路径【src/main/webapp】下新建文件夹static
	将课件resources中的system文件夹复制到这里
3.编写控制器SystemController跳转到后台首页【WEB-INF/view/index.jsp】
	@Controller

@RequestMapping("/system")
public class SystemController {

@RequestMapping("/index")
public String goSystemIndex(){
	return "index";
}

}
4.将后台首页【WEB-INF/view/index.html】转换成jsp
在相同位置新建一个相同名字的jsp
利用CV大法复制过来,jsp中只留下第一行<%@ page%>标签
删除掉以前的index.html
5.测试:http://localhost/system/index
看下css、js和图片路径是否有问题

功能:显示文章列表【Article】

以前显示的方式
	jstl + el【同步操作】
	jquery拼接出来的【可读性不高】
	使用GridManager展示列表数据
1.GridManager介绍
	开源免费的一个表格插件,使得我们展示列表数据非常方便
	2.0版本之后不依赖任何框架,意味着使用功能GridManager插件展示列表数据的时候,不需要导入其他js文件
	功能强大
		排序
		分页
		列拖拽
		自定义模板
		表头提示
		支持国际化
		等等......
2.GridManager使用
	1.引入资源
		gm.css
		gm.js
	2.html代码
		<div class="row">
<div class="col-md-12">
	<table id='table-demo-baseCode'></table>
</div>
3.js代码【基本实例】 网络地址,所以可以直接测试 4.后台返回数据格式必须是 data totals 5.后台返回指定的格式,使用Map

}
6.前台文章列表展示
字段匹配
文章标题
文章类型
浏览次数
创建时间
是否启用
代码:
document.querySelector(’#table-demo-baseCode’).GM({
gridManagerName: ‘demo-baseCode’, //指定表格实例的唯一标识
ajaxData: ‘/system/article/datagrid’, //前台发送ajax的请求
ajaxType: ‘POST’, //请求方式
columnData: [ //展示后台响应的json格式的数据
{
key: ‘title’, //join格式中数据的key值
text: ‘文章标题’ //表头的文本
},{
key: ‘type’,
text: ‘文章类型’
},{
key: ‘clickCount’,
text: ‘浏览次数’
},{
key: ‘createDate’,
text: ‘创建时间’
},{
key: ‘enable’,
text: ‘是否启用’
}
]
});
文本居中:
align:“center”
7.自定义单元格值和样式
操作
删除和更新按钮
自定义模板template
a标签
时间显示
在setter方法职工加上注解即可@JsonFormat
启用状态
true:绿色启用
false:红色禁用
8.文章类型显示
思路:在service中循环根据typeId查询文章内容对象设置回对象中
1.添加文章类型模块【mapper层代码】
新建ArticleTypeMapper接口:ArticleType findOne(Long id);
新建ArticleTypeMapper.xml



select * from t_article_type where id = #{id}


2.重构ArticleServiceImpl
根据typeId查询文章类型对象设置回文章对象中,再返回
@Autowired
private ArticleTypeMapper typeMapper;

@Override
public List

list() {
//所有的文章:只有typeId,没有类型名称
List
articles = mapper.list();
for (Article article : articles) {
long id = article.getTypeId();//获取所有文章的typeId
//根据typeId查询每一个文章对应的文章类型对象
ArticleType articleType = typeMapper.findOne(id);
//设置回去
article.setType(articleType);
}
return articles;
}
3.列表展示
自定义模板template
template: function(cell, row, index, key){
return cell.name;
}
3.画图说明执行流程

功能:文章列表分页

1.查看官网添加分页属性
2.分析分页属性
	显示分页条
		supportAjaxPage: true
			后台返回必须有totals
	自定义分页属性名
		currentPageKey: "localPage"
			请求参数中当前页key键值,默认为cPage
		pageSizeKey: "pageSize"
			请求参数中每页显示条数key健值, 默认为pSize
	自定义分页样式
		sizeData: [5,10,15,20]
			配置每页显示条数的下拉项,数组元素仅允许为正整数
	自定义分页初始值
		pageSize: 5
			配置初次进入时每页的显示条数,需要与sizeData中的值匹配
3.分析分页前台传递的数据
	控制台网络中查看请求参数
		localPage
			默认是第一页
		pageSize
			默认为属性pageSize的值5
4.后台接收请求和数据
	修改之前的方法【/system/article/datagrid】
	封装分页数据Bean【BaseQuery】 -- 【新建包:cn.itsource.cms.query】
		为什么封装?
			接收参数方便,直接对象接收
			其他类也有分页
		注意:新建query包之后,要在配置别名是配置扫描此包,否则mapper文件中不能有该包下的别名
	新建ArticleQuery继承BaseQuery
		这样的好处是
			将共用的分页信息localPage、pageSize放在共用类BaseQuery中
			将非共用的信息,例如每个模块的高级查询放在自己的类中,好维护
	封装后台返回数据Bean【PageBean<T>】
		将totals和data封装进来,好处是返回值方便,不在用Map返回totals和data了,这两个属性值不好记
		public class PageBean<T> {
//总条数
private Long totals = 0L;
//分页数据
private List<T> data = new ArrayList<>();
......

}
编写后台逻辑代码
Controller
@RequestMapping("/datagrid")
@ResponseBody
public PageBean

datagrid(Model model,ArticleQuery query){
PageBean
pageBean = service.selectPageList(query);
return pageBean;
}
Service
@Override
public PageBean
selectPageList(ArticleQuery query) {
Long totals = mapper.selectPageCount(query);
if(totals == 0l){
return new PageBean
();
}

List<Article> articles = mapper.selectPageList(query); 
for (Article article : articles) {
	Long typeId = article.getTypeId();
	ArticleType articleType = typeMapper.selectById(typeId);
	article.setType(articleType);
}
return new PageBean<Article>(totals,articles);

}
mapper
//分页查询:数据查询
List

selectPageList(ArticleQuery query);
//分页查询:数量查询
Long selectPageCount(ArticleQuery query);

Day2

1.高级查询

(1)高级查询html代码

请选择 技术文章 行业新闻 学科咨询
请选择 启用 禁用
查询

(2)Mapper和service
ArticleTypeMapper接口:
List findAll()
ArticleTypeMapper.xml:

<select id="findAll" resultType="cn.itsource.domain.ArticleType">
	select*from t_article_type
</select>

IArticleTypeService接口:
List findAll();
IArticleTypeService接口实现类:
@Autowired
private ArticleTypeMapper typeMapper;
@Override
public List findAll() {
return typeMapper.findAll();
}

(3)重构controller层的"/system/article/article"
public String toArticle(Map<String, Object> map) {
//查询所有
List list=typeService.findAll();
map.put(“list”, list);
return “article/article”;
}

(4)接受高级查询参数ArticleQuery
提供get,set,有参,无参方法
// 文章标题
private String title;
// 文章类型ID
private Long typeId;
// 默认启用状态
private Boolean enable;

(5)将高级查询中的数据提交到后台
高级查询的数据应该和分页信息以前提交到后台,因为点击高级查询,分页的数据应该是满足高级查询条件的
高级查询的查询按钮绑定单击事件:
//高级查询
KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲queryButton").o…("#queryForm").serializeObject();
//发送请求
GridManager.setQuery(“demo-ajaxPageCode”,da)

		})

注意:使用插件:jquery.jdirk.js,该插件是jQuery扩展插件,所以引入的时候必须在jQuery.js下面
自动获取:GridManager.setQuery(“demo-ajaxPageCode”,da)
好处:不管以后表单增加和删除查询项目,这个代码都不用变
(6)后台代码处理
ArticleServiceImpl.java:
@Autowired
private ArticleMapper mapper;
@Autowired
private ArticleTypeMapper typeMapper;
@Override
public PageBean

findAll(ArticleQuery query) {
//查询所有数据
Integer cont=mapper.findCount(query);
if (cont==0) {
return new PageBean<>();
}
//所有的文章:只有typeId,没有类型名称
List
list = mapper.findAll(query);
for (Article article : list) {
long id = article.getTypeId();//获取所有文章的typeId
//根据typeId查询每一个文章对应的文章类型对象
ArticleType articleType = typeMapper.getById(id);
//设置回去
article.setType(articleType);
}
return new PageBean<>(cont, list);
}

(7)Mapper.xml动态sql书写

<select id="findAll" resultType="cn.itsource.domain.Article">
select *from t_article
<include refid="nb"></include>
 limit #{begin},#{pageSize}
</select>

<!-- Integer findCount(ArticleQuery query); -->
<select id="findCount" resultType="int">
	SELECT COUNT(id) from t_article
	<include refid="nb"></include>
</select>
<sql id="nb">
	<where>
		<if test="typeId!=null">
			and typeId=${typeId}
		</if>
		<if test="enable!=null">
			and enable=${enable}
		</if>
		<if test="title!=null and ''!=title.trim()">
			and title like concat('%',trim(#{title}),'%')
		</if>
	</where>
</sql>

2.删除

(1)给删按钮添加data-id属性
'删除  ’

(2)删除时的模态框

<div class="modal fade" id="delModel">
	<div class="modal-dialog">
		<div class="modal-content message_align">
			<div class="modal-header">
				<button type="button" class="close" data-dismiss="modal" aria-label="Close">
					<span aria-hidden="true">×</span>
				</button>
			</div>
			<div class="modal-body">
					<h5 style="color: red">您确认要删除吗?</h5>
			</div>
			<div class="modal-footer">
				<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
				<a href="javascript:void(0);" id="delModelButton" class="btn btn-success">确定</a>
			</div>
		</div><!-- /.modal-content -->
	</div><!-- /.modal-dialog -->

(3)删除按钮添加点击事件,动态生成需要用事件委托
//删除,动态生成时间绑定
KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲table-demo-ajax…(this).data(“id”)
//弹出模态框
$("#delModel").modal(“show”)
//清空
$("#delModelButton").off();
//给确定删除按钮添加点击事件
$("#delModelButton").on(“click”,function(){
//发送请求
$.ajax({
type:‘post’,
url:’/system/article/del’,
data:{“id”:id},
dataType: ‘json’,
success: function(msg){
if(msg.success){
//关闭模态框
$("#delModel").modal(“hide”)
//刷新页面
GridManager.refreshGrid(‘demo-ajaxPageCode’,true);
}else{
alert(msg.error)
}
}
})
})
})

(4)后台处理请求
Controller:
@RequestMapping("/del")
@ResponseBody
public Ajax dele(Long id){
try {
service.dele(id);
return new Ajax();
} catch (Exception e) {
e.printStackTrace();
return new Ajax(false, “删除失败”);
}
}

(5)AjaxResult封装
package cn.itsource.util;
public class Ajax {
private Boolean success=true;
private String error;
public Ajax() {
super();
// TODO Auto-generated constructor stub
}
public Ajax(Boolean success, String error) {
super();
this.success = success;
this.error = error;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
@Override
public String toString() {
return “Ajax [success=” + success + “, error=” + error + “]”;
}
}

3.添加和修改

(1)添加和修改的模态框

(2)给添加按和修改钮添加属性
添加按钮:
ID==“addButton”
修改按钮:
“修改”;

(3)给修改按钮添加点击事件
//修改
KaTeX parse error: Expected '}', got 'EOF' at end of input: …息 var obj1=(this).data(“obj”)
//回显数据
$("#saveForm").setForm(obj1);
//弹出模态框
$("#saveModel").modal(“show”)
})
动态生成,用事件委托
(4)给添加按钮添加点击事件
//添加,动态生成,事件委托
$(“body”).on(“click”,"#addbtn",function(){
//清除缓存
$("#saveForm")[0].reset();
//清空隐藏域
$("#yid").val("");
//弹出模态框
$("#saveModel").modal(“show”)
})
动态生成,用事件委托

(5)给模态框中的确定按钮添加点击事件
//确定按钮,保存
$("#saveButton").on(“click”,function(){
$.ajax({
type:‘post’,
url: ‘/system/article/save’,
data: $("#saveForm").serialize(),//传入全部数据,
dataType: ‘json’,
success: function(msg){
if(msg.success){
//关闭模态框
$("#saveModel").modal(“hide”)
//刷新页面
GridManager.refreshGrid(‘demo-ajaxPageCode’);
}else{
alert(msg.error)
}
}
})
})

(6)后台代码
①Mapper
ArticleMapper.java:
void addById(Article article);
void update(Article article);
ArticleMapper.xml:

insert into t_article (title,url,typeId,clickCount,content,enable,createDate) values(#{title},#{url},#{typeId},#{clickCount},#{content},#{enable},#{createDate}) update t_article set title=#{title},url=#{url},typeId=#{typeId},clickCount=#{clickCount},content=#{content},enable=#{enable} where id=#{id}

②Service
IArticleService.java:
void saveById(Article article);
ArticleServiceImpl.java:
@Override
public void saveById(Article article) {
if (article.getId()==null) {
mapper.addById(article);
}else {
mapper.update(article);
}
}
添加和删除是根据获取id来判断是添加还是修改
③Controller
@RequestMapping("/save")
@ResponseBody
public Ajax saveById(Article article){
try {
service.saveById(article);
return new Ajax() ;
} catch (Exception e) {
e.printStackTrace();
return new Ajax(false, “保存失败”);
}
}

(7)注意
clearForm()、ajaxSubmit()都是jquery-form.js插件的方法
setForm()是form-load.js插件的方法

Day3

1.抽取公共资源
2.JS分离
3.前端首页文章列表展示
4.页面静态化
.1FreeMark
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据.全称:FreeMarker Template Language (FTL)。
4.1.1页面静态化技术编程步骤
重要:模板(.ftl)和数据(Map对象或Java实体 ,但是List集合不行)
1.导入freemarker.jar
2.获取模板(Template)对象
获取Configuration对象 – 为了获取模板对象
设置默认加载路径
设置默认编码
获取模板
3.准备数据map java实体对象
4.template.process()生成静态资源
5.创建xxx.ftl模板模板中使用el表达式获取数据
6.测试运行
1.导入freemarker.jar
// 2.获取模板(Template)对象
// 获取Configuration对象 – 为了获取模板对象
Configuration config = new Configuration(Configuration.VERSION_2_3_28);
// 设置默认加载路径
File file = new File(“src/main/webapp/static/template”);
config.setDirectoryForTemplateLoading(file);
// 设置默认编码
config.setDefaultEncoding(“UTF-8”);
// 获取模板
Template template = config.getTemplate(“test.ftl”);
// 3.准备数据
// map
// java实体对象
ArticleType type = new ArticleType(1L, “郭涛我沃尔”, “爱吃雀儿”);
// 4.template.process()生成静态资源
//生成的html文件路径和名字
File file2 = new File(file, System.currentTimeMillis()+".html");
//输出流
FileWriter out = new FileWriter(file2);
template.process(type, out);
// 5.创建xxx.ftl模板
// 模板中使用el表达式获取数据
//关流
out.close();
// 6.测试运行
}
4.2工具封装

public class FreeMarkerUtil {
public static String creatTemplate(String path,String name,Object data,String suffix) {
FileWriter out = null;
try {
// 2.获取模板(Template)对象
// 获取Configuration对象 – 为了获取模板对象
Configuration config = new Configuration(Configuration.VERSION_2_3_28);
// 设置默认加载路径
File file = new File(path);
config.setDirectoryForTemplateLoading(file);
// 设置默认编码
config.setDefaultEncoding(“UTF-8”);
// 获取模板
Template template = config.getTemplate(name);
// 4.template.process()生成静态资源
//生成的html文件路径和名字
String url=System.currentTimeMillis()+suffix;

		File file2 = new File(file, url);
		//输出流
		out = new FileWriter(file2);
		template.process(data, out);

// 5.创建xxx.ftl模板
// 模板中使用el表达式获取数据
return url;
// 6.测试运行
} catch (Exception e) {
// TODO: handle exception
}finally {
//关流
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
}

5.功能:添加和更新操作时生成静态页面

Controller层:
@RequestMapping("/save")
@ResponseBody
public Ajax saveById(Article article,HttpServletRequest req){
System.out.println(article);
try {
service.save(article,req);
return new Ajax();
} catch (Exception e) {
e.printStackTrace();
return new Ajax(false,“删除失败”);
}
}
Service的save方法:
@Override
public void save(Article article,HttpServletRequest req) {
//获取路径
String path = req.getServletContext().getRealPath("/static/template");
File file = new File(path);
//判断此路径有没有这个文件,如果没有就创建一个
if (!file.exists()) {
file.mkdirs();
}
//页面静态化
String url = FreeMarkerUtil.creatTemplate(path, “article.ftl”, article, “.html”);
article.setUrl(url);
if (article.getId()==null) {
mapper.add(article);
}else {
// 修改
// 删除之前的url
// 根据id查询url
Article bArticle=mapper.findById(article.getId());
String url2 = bArticle.getUrl();
File file2 = new File(path, url2);
if (file2.exists()) {
file2.delete();
}
mapper.updata(article);
}

}

ArticleMapper.xml:

<select id="findById" resultType="cn.itsource.domain.Article" >
	select*from t_article where id=#{id}
</select>

6.功能:删除操作时静态页面的处理

Controller层:
@RequestMapping("/del")
@ResponseBody
public Ajax del(Long id,HttpServletRequest req){
try {
service.del(id,req);
return new Ajax();
} catch (Exception e) {
return new Ajax(false, “删除失败”);
}
}

Service层:

@Override
public void del(Long id,HttpServletRequest req) {
//先查询所有文件
Article article = mapper.findById(id);
String url = article.getUrl();
String path = req.getServletContext().getRealPath("/static/template");
File file = new File(path, url);
if (file.exists()) {
file.delete();
}
mapper.del(id);
}

Day4

1.功能:浏览次数或点击次数的实现

(1)思路
刷新页面,拿到url参数,发送异步请求,查询数据库,然后更新数据库,将修改的对象返回到页面,更新页面
(2)模板JS代码

(3)Controller
@Controller
@RequestMapping("/system/home")
public class HomeController {
@RequestMapping("/update")
@ResponseBody
public Article upDate(String url){
return service.updateArticleUrl(url);
}
}
(4)Service
@Override
public Article updateArticleUrl(String url) {
//先查询本条url
Article article = mapper.findByUrl(url);
//设置点击次数
article.setClickCount(article.getClickCount()+1);
mapper.update(article);
return article;
}

(5)Mapper

<select id="findByUrl" resultType="cn.itsource.domain.Article">
select*from t_article where url=#{url}
</select>

2.富文本编辑器的使用

(1)什么是UEditor

UEditor是百度的一款所见即所得的编辑器(富文本编辑器),大家可以看看一下这款编辑器的效果

(2)UEditor的使用步骤
①导入UEditor文件

②导入jar包

③引入UEditor文件

(3)UEditor项目集成
①文章界面代码

②添加弹出框清空UEditor
$("#saveForm]").val(“clearForm”);
var ue = UE.getEditor(‘container’);
//清空UEditor中的内容
ue.ready(function() {
ue.setContent("");
});
$("#openModal").modal(“show”);

③修改弹出框回显UEditor内容
//修改代码 $("#table-demo-baseCode").on(“click”,“a[data-article]”,function(){
//重置
$("#saveForm]").val(“clearForm”);
//回显数据
var article = $(this).data(“article”);
//获取UEDitor对象
var ue = UE.getEditor(‘container’);
//加载内容回显
ue.ready(function() {
ue.setContent(article.content);
});
$("#saveForm input[name=‘title’]").val(article.title);
$("#saveForm select[name=‘typeId’]").val(article.typeId);
$("#saveForm input[name=‘url’]").val(article.url);
$("#saveForm input[name=‘id’]").val(article.id);
$("#saveForm input[name=‘enable’]").val([article.enable?1:0]);
$("#saveForm textArea").val(article.content);
$("#openModal").modal(“show”);
});

3.功能:轮播图的列表显示和高级查询

(1)domain
public class Slide {
private Long id;
//图片名
private String name;
//图片路径
private String path;
//创建时间
private Date createDate = new Date();
//默认启用状态
private Boolean enable;
}

(2)在leftMenu.jsp中追加轮播图模块

(3)文件复制和准备
复制一个article.jsp改名为slide.jsp
.复制一个article.js修改成slide.js,并在slide.jsp中引入该js
富文本的配置全部删除编写slide的实体类【参考课件】
(4)Controller
@Controller
@RequestMapping("/system/slide")
public class SlideController {
@Autowired
private ISlideService service;

@RequestMapping("/find")
@ResponseBody
public	PageBean<Slide> findAll(SlideQuery query){
	return service.findAll(query);
}

/**
 * 
 * @Description:(跳转页面)
 * @param:@return   
 * @return:String  
 * @author:yy
 * @date:2020年9月7日
 * @version:V1.0
 */
@RequestMapping("/slide")
public String toSlide() {
	return "slide/slide";
}

(5)Service
@Service
public class SlideServiceImpl implements ISlideService {
@Autowired
private SlideMapper mapper;
@Override
public PageBean findAll(SlideQuery query) {
//查询所有数据条数
Integer cont=mapper.findCount(query);
if (cont==0) {
return new PageBean<>();
}
//所有的文章:只有typeId,没有类型名称
List list = mapper.findAll(query);
return new PageBean<>(cont, list);
}

(6)Mapper

<select id="findCount" resultType="int">
	select count(id) from t_slide
	<include refid="nb"></include>
</select>
<select id="findAll" resultType="cn.itsource.domain.Slide">
	select *from t_slide 
	<include refid="nb"></include>
	limit #{begin},#{pageSize}
</select>
<sql id="nb">
	<where>
		<if test="enable!=null">
			and enable=${enable}
		</if>
		<if test="name!=null and ''!=name.trim()">
			and name like concat('%',trim(#{name}),'%')
		</if>
	</where>
</sql>

(7)前台展示

/* Gridmanager展示数据的 */
document.querySelector(’#table-demo-baseCode’).GM({
gridManagerName: ‘demo-baseCode’,//gridmanager对应的名字
ajaxData: ‘/system/slide/datagrid’,//发送的url地址
ajaxType: ‘POST’,//请求类型
supportAjaxPage: true,//支持分页
height: ‘100%’,//配置表格区域的高度,需要带单位,超过这个高度会出现滚动条
currentPageKey: ‘localPage’,//请求参数中当前页key键值,默认为cPage,现在修改成了localPage
pageSizeKey: ‘pageSize’,//请求参数中每页显示条数key健值, 默认为pSize,现在修改成了pageSize
pageSize: ‘5’,//配置初次进入时每页的显示条数,需要与sizeData中的值匹配
sizeData: [5,10,15,20],//配置每页显示条数的下拉项,数组元素仅允许为正整数
columnData: [
{
key: ‘name’,
text: ‘图片名’,
align:‘center’
},{
key: ‘path’,
text: ‘图片’,
align:‘path’,
template: function(cell, row, index, key){
return ‘没有图片’;
}
},{
key: ‘createDate’,
text: ‘创建时间’,
align:‘center’
},{
key: ‘enable’,
text: ‘是否启用’,
align:‘center’,
//cell 就代表是enable对应的值 row:当前行的值 index:当前行对应的索引
//key 就是字段对应的值
template: function(cell, row, index, key){
return cell?“启用”:“禁用”
}
},{
key: ‘id’,
text: ‘操作’,
align:‘center’,
template: function(cell, row, index, key){
return "删除 "+
“修改”
}
}
]
});

(8)高级查询表单

请选择 启用 禁用
查询 添加

(9)高级查询js代码
//按钮添加点击事件
//高级查询
KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲queryButton").c…("#queryForm").serializeObject();
//发送请求
GridManager.setQuery(“demo-ajaxPageCode”,datas);
})

4.功能:文件上传功能

(1)文件上传三要素
①Post请求
②enctype=“multipart/form-data”
③type="file"

(2)配置文件上传解析器

(3)模态框点击事件绑定
//保存
$("#saveButton").on(“click”,function(){
//发送请求
/* 添加和更新模态框点击确定时绑定事件请求后台 */
$("#saveForm").ajaxSubmit({
success:function(data){
if(data.success){
//关闭添加和修改模态框
$("#saveModal").modal(“hide”);
//刷新表格
GridManager.refreshGrid(‘demo-ajaxPageCode’);
}else{
alert(data.error);
}
}
})

(4)Controller层
参考article
(5)Service
@Override
public void save(Slide slide, HttpServletRequest req, MultipartFile photo) throws Exception {
//判断是否有photo
if (photo!=null) {
//输入流
InputStream input = photo.getInputStream();

		//获取路径
		String realPath = req.getServletContext().getRealPath("/static/upload");
		File file = new File(realPath);
		//判断有无次路径
		if (!file.exists()) {
			file.mkdirs();
		}
		//获取图片的名字
		String filename = photo.getOriginalFilename();
		//截取后缀
		String suffix = filename.substring(filename.lastIndexOf("."));
		//拼接需要长传到后台的名字
		String name= System.currentTimeMillis()+suffix;
		
		
		//输出流
		FileOutputStream output=new FileOutputStream(new File(realPath, name));
		//核心代码
		IOUtils.copy(input, output);
		//关流
		input.close();
		output.close();
		//把新数据传入进去
		slide.setName(name);
		slide.setPath("/static/upload/"+name);
	}
	if (slide.getId()==null) {
		if (photo!=null) {
			mapper.add(slide);
		}
	}
	
}

(6)Mapper

<insert id="add"> 
	insert into t_slide (name,path,createDate,enable)
	values(#{name},#{path},#{createDate},#{enable})
</insert>

Day5

1.lide修改模块

(1)思路:点击更新按钮,弹出模态框,数据做回显,点击模态框的确认按钮,将数据提交到后台做更新
(2)Controller层
@RequestMapping("/save")
@ResponseBody
public Ajax saveById(Article article,HttpServletRequest req){
try {
service.saveById(article,req);
return new Ajax() ;
} catch (Exception e) {
e.printStackTrace();
return new Ajax(false, “保存失败”);
}
}

(3)Service层
@Override
public void save(Slide slide, HttpServletRequest req, MultipartFile photo) throws Exception {
//获取路径

	String realPath = req.getServletContext().getRealPath("/static/upload");
	//判断是否有photo
	if (photo!=null) {
		//输入流
		InputStream input = photo.getInputStream();
		
		File file = new File(realPath);
		//判断有无次路径
		if (!file.exists()) {
			file.mkdirs();
		}
		//获取图片的名字
		String filename = photo.getOriginalFilename();
		//截取后缀
		String suffix = filename.substring(filename.lastIndexOf("."));
		//拼接需要长传到后台的名字
		String name= System.currentTimeMillis()+suffix;
		//输出流
		FileOutputStream output=new FileOutputStream(new File(realPath, name));
		//核心代码
		IOUtils.copy(input, output);
		//关流
		input.close();
		output.close();
		//把新数据传入进去
		slide.setName(name);
		slide.setPath("/static/upload/"+name);
	}
	if (slide.getId()==null) {
		if (photo!=null) {
			mapper.add(slide);
		}
	}else {
		Slide dslide=mapper.findOne(slide.getId());
		mapper.update(slide);
		if (photo!=null) {
			File file = new File(realPath,dslide.getName());
			if (file.exists()) {
				file.delete();
			}
		}
	}
	
}

(4)Mapper

<select id="findOne" resultType="cn.itsource.domain.Slide">
	select *from t_slide where id=#{id}
</select>
<!-- 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>

2.Slide删除模块

(1)思路:点击删除,单击事件,发送异步请求,并传递id,后台删除
(2)Controller
@RequestMapping(“del”)
@ResponseBody
public Ajax dele(Long id,HttpServletRequest req){
try {
service.dele(id,req);
return new Ajax();
} catch (Exception e) {
return new Ajax(false, “删除失败”);
}
}

(3)Service
@Override
public void dele(Long id, HttpServletRequest req) {
Slide slide = mapper.findOne(id);
mapper.deleById(id);
String realPath = req.getServletContext().getRealPath("/static/upload");
File file = new File(realPath,slide.getName());

	if (file.exists()) {
		file.delete();
	}
}

(4)Mapper

<delete id="deleById">
	delete from t_slide where id=#{id}
</delete>

3.轮播图显示

(1)JS
$(function() {
//发送请求
$.ajax({
type:‘post’,
url:‘system/home/findAll’,
dataType:‘json’,
success:function(msg){
$.each(msg,function(i,obj){
$(".swiper-wrapper").append(’<a target="_blank" href="" class=“swiper-slide swiper-lazy”’
+‘data-background="’+obj.path+’">

’)
})

(2)Controller
@RequestMapping("/findAll")
@ResponseBody
public List findAllSlide(){
return slideService.findAllSlide();
}

(3)Service
@Override
public List findAllSlide() {

	return mapper.findAllSlide();
}

(4)Mapper

<select id="findAllSlide" resultType="cn.itsource.domain.Slide">
	select *from t_slide 
</select>

4.无状态Http协议

(1)什么是会话
定义
可简单理解为:用户开一个浏览器,访问某一个web站点,在这个站点点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一次会话。
例:
输入网址进入优酷,然后我在这优酷这个网站里面跳过来跳过去。
访问的时候,这个会话就已经开始……
关闭浏览器的时候,这个会话就结束……

(2)会话跟踪
HTTP是无状态协议,没有记忆力,不知道哪一个客户端请求了自己,每个请求之间无法共享数据。这就无法知道会话什么时候开始,什么时候结束,也无法确定发出请求的用户身份。

那么我们已经看到了上述图片是可以记住,意思就是别个解决了http无状态的情况。那么我们怎么来解决这个问题呢?

(3)解决HTTP无状态的问题
把我们需要保持状态的数据在每次跳转的时候都传到另一个页面上去

EmailMainServlet

EmailListServlet

EmaiSingleServlet.java

使用上面这种方式会有一些问题

  1. 有数据的限制
  2. 操作起来太麻烦了(每次跳转都需要带着参数)
  3. 安全问题(所有的数据都显示在地址栏的)

怎么解决安全问题呢? -> 不要让他显示地址栏
使用Cookie

5.Cookie和Session

(1)Cookie
①Cookie是什么
将一小段文本信息保存在客户端浏览器中的一种会话跟踪技术
②执行原理
1.当浏览器第一次发送请求服务器
2.遇到服务器端创建Cookie的代码,就会用set-Cookie的方法将Cookie的数据传回给浏览器
3.浏览器默认保存在内存中
4.只要浏览器没有关闭过,当第二次请求时,浏览器会自动将Cookie的数据以Cookie的方式传回给服务器
5.至于服务器是否获取和获取出来做什么,跟后期业务有关
③Cookie的创建
// 创建cookie
Cookie c1 = new Cookie(“id”, “01”);
Cookie c2 = new Cookie(“name”, URLEncoder.encode(“郭儿”, “UTF-8”));//有中文必须编码
Cookie c3 = new Cookie(“sex”, URLEncoder.encode(“男”, “UTF-8”));
Cookie c4 = new Cookie(“age”, “16”);

④Cookie添加
// 添加到浏览器端
resp.addCookie(c1);
resp.addCookie(c2);
resp.addCookie(c3);
resp.addCookie(c4);

⑤Cookie获取
@RequestMapping("/get1")
public void getCookie2(HttpServletRequest req) throws Exception{
//获取cookie
Cookie[] cookies = req.getCookies();
//数组循环
for (Cookie cookie : cookies) {
System.out.println(cookie.getName());
System.out.println(URLDecoder.decode(cookie.getValue(), “UTF-8”));
}
}

⑥中文乱码
cookie的name值不能是中文
value如果是中文需要编码:URLEncoder.encode(“中文”,“UTF-8”)
解码:URLDecoder.decode(c.getValue(),“UTF-8”)
⑦声明周期
生命周期:指的是Cookie中的数据能保存多久。默认请求下:浏览器会将Cookie保存在内存中,只有浏览器不关闭,数据都在。直到浏览器关闭,数据消失。
如果设置了setMaxAge(int n)
n<0:默认状态,保存在内存中,关闭浏览器数据失效
n=0:立即删除
n>0:保存在硬盘中,持续n秒(这时跟浏览器关不关闭无关)
直到时间走完之后自动删除

⑧更新
第一种:先获取相应的value – 遍历 – 判断 – setValue(String value)
第二种:添加一个相同name值的Cookie,直接覆盖
⑨Cookie不能跨路径获取
Cookie c1 = new Cookie(“name”, URLEncoder.encode(“汤姆”,“UTF-8”));
c1.setPath("/");//设置/跟路径有效
⑩优缺点
缺点:
1.数据保存在浏览中,数据容易丢失,数据容易被获取,不安全
Cookie可以被禁用
2.保存数据类型有限,只能是字符串
3.保存的数据大小有限制,大约是4kb左右
优点:减轻了服务器的压力
(2)Session
①什么是session
将数据保存在服务器端的会话跟踪技术
jsessoinid就是每一个session对象的id值,它是依赖Cookie进行传递的
②执行原理:
1.当浏览器第一次发送请求服务器
2.遇到服务器端创建Session的代码,就会创建一个Session对象,然后为该Session对象分配一个id即为jsessionId,并以set-Cookie的方式将该id传回给浏览器,浏览器保存起来
3.只要浏览器没有关闭过,当第二次请求时,会自动将jsessionId以Cookie的方式传回给服务器,服务器根据该jsessionId去服务器查询,查到了使用
4.至于服务器是否获取和获取出来做什么,跟后期业务有关
③Session创建
// 获取session // 没有则创建
HttpSession session = req.getSession();
自动创建
直接访问JSP
④Session使用
@RequestMapping("/add")
public void createrSession(HttpSession session1,HttpServletRequest req,HttpServletResponse resp){
// 获取session // 没有则创建
HttpSession session = req.getSession();
// 存储信息
session.setAttribute(“name”, “亲”);
session.setAttribute(“age”, 18);
session.setAttribute(“sex”, “女”);
session.setAttribute(“address”, “东莞”);
//移除
session.removeAttribute(“sex”);
// 获取信息
Object name = session.getAttribute(“name”);
Object age = session.getAttribute(“age”);
Object sex = session.getAttribute(“sex”);
Object address = session.getAttribute(“address”);
System.out.println(name);
System.out.println(age);
System.out.println(sex);
System.out.println(address);

⑤Session生命周期
sesion的生命周期
出生:创建Session对象
invalidate():销毁session对象
数据保存的时间
出生:添加数据的时候
数据消失:过期时间结束
默认的过期时间是30分钟
从不操作开始计时
自定义
代码方式:session.setMaxInactiveInterval(int s)
web.xml方式:,单位是分钟
⑥优缺点
优点:
由于session是将数据保存在服务器端,安全性高相对较高
大小相对于Cookie来说大得多
数据类型没有限制
缺点:
可能会影响服务器的性能
(3)Session和cookie的区别
突破口:数据保存在哪里
Session:服务器 -> 安全 + 大小无限制 +类型无限制,但是会影响服务器性能
6.登录功能
(1)Controller
@RequestMapping(value="/login",method=RequestMethod.GET)
public String toLogin(){
return “login”;
}
@RequestMapping(value="/login",method=RequestMethod.POST)
@ResponseBody
public Ajax login(String username,String password,HttpServletRequest req){
try {
//查找当前数据
User user=service.findByName(username,password);
//把数据放到session中
req.getSession().setAttribute(“USER_IN_SESSION”, user);
return new Ajax();
} catch (Exception e) {
// TODO: handle exception
return new Ajax(false, e.getMessage());
}
}

(2)Service
@Override
public User findByName(String username, String password) throws Exception {
//根据用户名从数据库查找
User user=Mapper.findByUser(username);
if (user==null) {
throw new Exception(“没有该用户名”);
}else {
if (!user.getPassword().equals(password)) {
throw new Exception(“密码错误”);
}else {
return user;
}
}
}

(3)Mapper

<select id="findByUser" resultType="cn.itsource.domain.User">
	select *from t_user where username=#{username}
</select>

(4)Login.jsp

7.注销功能

(1)修改退出请求【/WEB-INF/views/common/header.jsp】

(2)Controller【UserController】 @RequestMapping("/logout") public String logout(HttpServletRequest req) { //重新跳转需要销毁之前的session req.getSession().invalidate(); return "login"; }

Day6

1.登录功能点击回车登录

//回车登录
$(document).on(“keypress”,function(msg){
if(msg.keyCode==13){
login();
}
})

2.登录功能记住我实现

(1)在login.jsp页面添加记住我的表单项属性

(2)Controller
//查找当前数据
User user=service.findByName(username,password);
//把数据放到session中
req.getSession().setAttribute(“USER_IN_SESSION”, user);
if (remember!=null) {
//创建cookie
Cookie c1 = new Cookie(“username”, username);
Cookie c2 = new Cookie(“password”, password);
//设置路径
c1.setPath("/");
c2.setPath("/");
//设置声明周期
c1.setMaxAge(7246060);
c2.setMaxAge(7
246060);
//添加到浏览器
resp.addCookie(c1);
resp.addCookie(c2);
}

(3)Login页面
//记住我
//截取
var arr=cookies.split(";");
for(var i in arr){
if(arr[i].indexOf(“username”)!=-1){
username=arr[i].substring(arr[i].lastIndexOf("=")+1);
$("#username").val(username);
}
if(arr[i].indexOf(“password”)!=-1){
password=arr[i].substring(arr[i].lastIndexOf("=")+1);
$("#password").val(password);
}
}
$("#remember").prop(“checked”,true)
}

3.取消记住我

(1)Controller代码
else {
//获取cookie
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals(“username”) || cookie.getName().equals(“password”)) {
//清除cookie
cookie.setMaxAge(0);
//设置路径
cookie.setPath("/");
//添加cookie
resp.addCookie(cookie);
}
}
}

(2)Login代码
else{
//取消记住我
$("#username").val("");
$("#password").val("");
//取消勾选
$("#remember").prop(“checked”,false)
}

4.登录拦截

(1)思路:编写拦截器,拦截请求,判断用户的登录状态【Session邦定值】,不为null,放行。如果为null,没有登录过,跳转到登录页面
(2)编写拦截器
package cn.itsource.cms.interceptor;
public class LoginInterceptor implements HandlerInterceptor{
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}

@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
		throws Exception {
}
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object obj) throws Exception {
	Object user = req.getSession().getAttribute(Constant.USER_IN_SESSION);
	if(user == null){
		resp.sendRedirect("/system/login");
		return false;
	}
	return true;
}

}

(3)配置拦截器

mvc:interceptors
mvc:interceptor
<mvc:mapping path="/system/**"/>
<mvc:exclude-mapping path="/system/login"/>

</mvc:interceptor>
</mvc:interceptors>

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要用 Go 语言实现一个内容管理系统 (CMS),你需要考虑以下几个方面: 1. 数据存储:你需要选择一种数据库,并使用 Go 语言来连接和操作数据库。常见的数据库有 MySQL、PostgreSQL 和 MongoDB。 2. 网站框架:你可以使用 Go 语言内置的 net/http 库来构建网站后端,也可以使用第三方框架,比如 Gin、Echo 和 Buffalo。 3. 网站布局和样式:你可以使用 HTML、CSS 和 JavaScript 来设计网站的布局和样式。 4. 网站功能:你可以根据需求来实现各种功能,比如文章发布、评论管理、用户注册登录等。 在开始实现之前,建议先了解 Go 语言的基础知识,包括变量、类型、流程控制、函数、指针等。同时,也建议了解一些常用的第三方库,比如用于数据库操作的 GORM 库和用于模板渲染的 html/template 库。 ### 回答2: 使用Go语言实现一个CMS系统是完全可行的。Go是一种现代化的编程语言,它具有高效的并发性能和简洁的语法,非常适合构建Web应用程序。 首先,我们可以使用Go的HTTP包来处理HTTP请求和响应。通过创建一个HTTP服务器,我们可以监听特定的端口,并对请求进行路由和处理。可以使用gorilla / mux库来进行路由器设置和管理。 接下来,我们可以设计和实现数据库模型。Go有很多流行的ORM(对象关系映射)库,如GORM和xorm。使用这些库,我们可以方便地将Go结构体映射到数据库表,并进行基本的CRUD(创建、读取、更新、删除)操作。 然后,我们可以创建处理程序来处理特定的请求,例如创建、编辑和删除内容。可以使用HTML模板引擎(如html / template)来生成动态的HTML页面,也可以使用Go的JSON库将数据以JSON格式返回给客户端。 为了保护用户登录和数据的安全,我们可以使用Go的加密库来存储和验证用户的密码,并使用会话管理库(如gorilla / sessions)来跟踪用户的认证状态。 最后,我们可以使用Go的测试框架(如testing / testing)来编写和运行单元测试和集成测试,以确保系统的正确性和稳定性。 总之,使用Go语言实现一个CMS系统是一项有趣且具有挑战性的任务。Go的简洁性、高效性和并发性能使其成为构建可扩展的Web应用程序的理想选择。 ### 回答3: 使用Go语言来实现一个CMS(内容管理系统)可以借助于一些Go语言的库和框架来快速搭建一个功能完善的CMS系统。 首先,可以使用Go的Web框架如Gin或Echo来处理HTTP请求和路由,这样能够方便地创建和管理不同页面的接口。 其次,可以使用Go的数据库驱动库如Gorm来连接数据库,如MySQL或PostgreSQL等,以存储和管理网站的数据。可以使用Gorm的模型和迁移功能来定义表结构和进行数据库迁移。 接下来,可以利用Go的模板引擎如html/template来生成动态页面,通过将数据库中的数据和模板结合,可以实现页面的渲染更新。 此外,由于CMS系统通常需要进行用户身份验证和授权管理,可以使用Go的身份验证和授权库如jwt-go或casbin来实现用户的登录、验证和权限管理功能。 同时,为了方便系统的扩展和维护,可以使用Go的依赖管理工具如Go Modules来管理项目的依赖关系。 总结起来,用Go实现一个CMS系统需要使用到Go语言的Web框架、数据库驱动库、模板引擎、身份验证与授权库等,通过这些工具可以方便地创建和管理网站的接口、数据库、页面、用户身份验证和权限管理等功能,从而实现一个功能完善的CMS系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值