【ssm个人博客项目实战07】博客的后台实现
2017-04-24 21:55
585 查看
在前面我们已经完成了博客类别的添加修改删除分页查询操作了,现在我们就来完成了博客的添加修改
首先创建t_blog表
id 博客主键
type_id为关联外键列 代表所属博客类别
然后创建对应的实体类
其中
blogType 是该博客所属的博客类型 属于多对一的关系
blogCount 博客数量,非博客实际属性,用于根据发布日期归档查询
releaseDateStr 发布日期的字符串,只取年月
接下来就是dao
接下来就dao对应mapper文件
为什么getTotal方法带参数呢,因为我需要实现模糊分页查询的功能的,所以你对应查询记录的总数也要带上参数。其中的 是mybatis提供给我们实现动态sql的工具
association : 一个复杂的类型关联;许多结果将包成这种类型
其中property实体类属性 column关联外键类 select给实体类属性初始化的方法 因为我们的实体类是BlogType对象 所以我们可以根据type_id的值从BlogTypeDao的getById方法把这条记录查询出来并且赋值给blogType属性
接下来就是service实现
直接下来就是controller的实现
这里主要注意一下json序列化的时候
//设置json序列化日期格式
JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;
设置序列化时date序列化的格式
如果不设置 时间戳的格式,
设置完格式化日期格式后 就使用该格式序列化日期
还有一个问题就是对象循环引用的问题
例如
循环引用:对象的属性之间存在相互引用导致循环,会引起StackOverFlow异常
例如:
fastjson支持循环引用/重复引用,并且是缺省打开的。
* 第一个例子序列化后输出结果为:{“1”:{},”2”:{“ref":".1”}}
第一个对象正常序列化,第二个对象则用引用表示
* 第二个列子序列化后输出结果为:{“1”:{“1”:{“$ref”:”..”}}}
全局配置关闭
当我们的博客属于同一个类型的时候 也就是说blogType属性相同的时候就会出现循环引用的情况 这样我们就需要关闭循环引用了。
这样控制层写完了
接下来我们可以使用postman测试了
下一节我们将实现博客的前台实现
首先创建t_blog表
CREATE TABLE `t_blog` ( `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '博客类型', `title` VARCHAR(200) NOT NULL COMMENT '博客题目', `summary` VARCHAR(400) DEFAULT NULL COMMENT '博客摘要', `releaseDate` DATETIME DEFAULT NULL COMMENT '发布日期', `clickHit` INT(11) DEFAULT NULL COMMENT '评论次数', `replyHit` INT(11) DEFAULT NULL COMMENT '回复次数', `content` TEXT COMMENT '博客内容', `keyWord` VARCHAR(200) DEFAULT NULL COMMENT '关键字', `type_id` INT(11) DEFAULT NULL COMMENT '外键关联博客类别', PRIMARY KEY (`id`), KEY `type_id` (`type_id`), CONSTRAINT `t_blog_ibfk_1` FOREIGN KEY (`type_id`) REFERENCES `t_blogtype` (`id`) ) ENGINE=INNODB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8;
id 博客主键
type_id为关联外键列 代表所属博客类别
然后创建对应的实体类
package ssm.blog.entity; import java.util.Date; import java.util.LinkedList; import java.util.List; /** * @Description 博客实体 * @author xp * */ public class Blog { private Integer id; private String title; private String summary; private Date releaseDate; private Integer clickHit; private Integer replyHit; private String content; private String keyWord; //关键字,用空格隔开 private BlogType blogType; //博客类型 private Integer blogCount; //博客数量,非博客实际属性,用于根据发布日期归档查询 private String releaseDateStr; //发布日期的字符串,只取年月 private List<String> imageList = new LinkedList<String>();//博客里存的图片,主要用于展示缩略图 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getSummary() { return summary; } public void setSummary(String summary) { this.summary = summary; } public Date getReleaseDate() { return releaseDate; } public void setReleaseDate(Date releaseDate) { this.releaseDate = releaseDate; } public Integer getClickHit() { return clickHit; } public void setClickHit(Integer clickHit) { this.clickHit = clickHit; } public Integer getReplyHit() { return replyHit; } public void setReplyHit(Integer replyHit) { this.replyHit = replyHit; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getKeyWord() { return keyWord; } public void setKeyWord(String keyWord) { this.keyWord = keyWord; } public BlogType getBlogType() { return blogType; } public void setBlogType(BlogType blogType) { this.blogType = blogType; } public List<String> getImageList() { return imageList; } public void setImageList(List<String> imageList) { this.imageList = imageList; } }
其中
blogType 是该博客所属的博客类型 属于多对一的关系
blogCount 博客数量,非博客实际属性,用于根据发布日期归档查询
releaseDateStr 发布日期的字符串,只取年月
接下来就是dao
package ssm.blog.dao; import java.util.List; import java.util.Map; import ssm.blog.entity.Blog; /** * @Description 博客Dao接口 * @author xp * */ public interface BlogDao { // 分页查询博客 public List<Blog> listBlog(Map<String, Object> map); // 获取总记录数 public Long getTotal(Map<String ,Object> map); // 根据博客类型的id查询该类型下的博客数量 public Integer getBlogByTypeId(Integer typeId); //添加博客 public Integer saveBlog(Blog blog); //更新博客 public Integer updateBlog(Blog blog); //删除博客 public Integer deleteBlog(Integer id); //通过id获取博客 public Blog getById(Integer id);
接下来就dao对应mapper文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="ssm.blog.dao.BlogDao"> <resultMap type="Blog" id="BlogResult"> <id property="id" column="id"/> <result property="title" column="title"/> <result property="summary" column="summary"/> <result property="releaseDate" column="releaseDate"/> <result property="clickHit" column="clickHit"/> <result property="replyHit" column="replyHit"/> <result property="content" column="content"/> <result property="keyWord" column="keyWord"/> <association property="blogType" column="type_id" select="ssm.blog.dao.BlogTypeDao.getById"> </association> </resultMap> <select id="listBlog" parameterType="Map" resultMap="BlogResult"> SELECT * FROM t_blog <where> <if test="title!=null and title!=''"> and title like "%"#{title}"%" </if> <if test="typeId!=null and typeId!=''"> and type_id=#{typeId} </if> <if test="releaseDateStr!=null and releaseDateStr!=''"> and DATE_FORMAT(releaseDate,'%Y年%m月')=#{releaseDateStr} </if> </where> ORDER BY releaseDate DESC <if test="start!=null and end!=null"> limit #{start},#{end} </if> </select> <select id="getTotal" parameterType="Map" resultType="Long"> SELECT COUNT(*) FROM t_blog <where> <if test="title!=null and title!=''"> and title like "%"#{title}"%" </if> <if test="typeId!=null and typeId!=''"> and type_id=#{typeId} </if> <if test="releaseDateStr!=null and releaseDateStr!=''"> and DATE_FORMAT(releaseDate,'%Y年%m月')=#{releaseDateStr} </if> </where> </select> <select id="getBlogByTypeId" parameterType="Integer" resultType="Integer"> select count(*) from t_blog where type_id=#{typeId} </select> <insert id="saveBlog" parameterType="Blog" keyProperty="id" useGeneratedKeys="true"> insert into t_blog VALUES (NULL ,#{title},#{summary},now(),0,0,#{content},#{keyWord},#{blogType.id}) </insert> <update id="updateBlog" parameterType="Blog"> update t_blog <set> <if test="title!=null and title!=''"> title=#{title}, </if> <if test="summary!=null and summary!=''"> summary=#{summary}, </if> <if test="content!=null and content!=''"> content=#{content}, </if> <if test="blogType.id!=null"> type_id=#{blogType.id}, </if> <if test="clickHit!=null"> clickHit=#{clickHit}, </if> <if test="replyHit!=null"> replyHit=#{replyHit}, </if> <if test="keyWord!=null and keyWord!=''"> keyWord=#{keyWord}, </if> </set> where id=#{id} </update> <delete id="deleteBlog" parameterType="java.lang.Integer"> DELETE FROM t_blog where id=#{id} </delete> <select id="getById" parameterType="java.lang.Integer" resultMap="BlogResult"> SELECT * from t_blog where id=#{id} </select> </mapper>
为什么getTotal方法带参数呢,因为我需要实现模糊分页查询的功能的,所以你对应查询记录的总数也要带上参数。其中的 是mybatis提供给我们实现动态sql的工具
association : 一个复杂的类型关联;许多结果将包成这种类型
其中property实体类属性 column关联外键类 select给实体类属性初始化的方法 因为我们的实体类是BlogType对象 所以我们可以根据type_id的值从BlogTypeDao的getById方法把这条记录查询出来并且赋值给blogType属性
接下来就是service实现
package ssm.blog.service; import java.util.List; import java.util.Map; import ssm.blog.entity.Blog; import ssm.blog.entity.PageBean; /** * @author xp * @Description 博客Service接口 */ public interface BlogService { // 分页查询博客 public List<Blog> listBlog(Map<String,Object> map); // 分页查询博客 public PageBean<Blog> listBlog(String title,PageBean<Blog> pageBean); // 根据博客类型的id查询该类型下的博客数量 public Integer getBlogByTypeId(Integer typeId); //添加博客 public Integer saveBlog(Blog blog); //更新博客 public Integer updateBlog(Blog blog); //通过id删除博客 public Integer deleteBlog(Integer id); //通过id获取博客 public Blog getById(Integer id); long getTotal(Map<String, Object> map);
package ssm.blog.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Service; import ssm.blog.dao.BlogDao; import ssm.blog.entity.Blog; import ssm.blog.entity.PageBean; import ssm.blog.service.BlogService; /** * @Description 博客Service实现类 * @author xp * */ @Service("blogService") public class BlogServiceImpl implements BlogService { @Resource private BlogDao blogDao; public PageBean<Blog> listBlog(String title, PageBean<Blog> pageBean) { Map<String,Object> map = new HashMap<String,Object>(); //设置查询条件 map.put("title",title); //总记录放入pageBean pageBean.setTotal(blogDao.getTotal(map)); map.put("start",pageBean.getStart()); map.put("end",pageBean.getEnd()); //把分页结果放入pageBean pageBean.setResult(blogDao.listBlog(map)); return pageBean; } public List<Blog> listBlog(Map<String,Object> map) { return blogDao.listBlog(map); } public Integer getBlogByTypeId(Integer typeId) { return blogDao.getBlogByTypeId(typeId); } public Integer saveBlog(Blog blog) { return blogDao.saveBlog(blog); } public Integer updateBlog(Blog blog) { return blogDao.updateBlog(blog); } public Integer deleteBlog(Integer id) { return blogDao.deleteBlog(id); } public Blog getById(Integer id) { return blogDao.getById(id); } public long getTotal(Map<String, Object> map) { return blogDao.getTotal(map); } }
直接下来就是controller的实现
package ssm.blog.controller.admin; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import ssm.blog.entity.Blog; import ssm.blog.entity.PageBean; import ssm.blog.lucene.BlogIndex; import ssm.blog.service.BlogService; import ssm.blog.service.CommentService; import ssm.blog.util.ResponseUtil; /** * @author xp * @Description 管理员博客Controller层 */ @Controller @RequestMapping("/admin/blog") public class BlogAdminController { @Resource private BlogService blogService; //后台分页查询博客信息 @RequestMapping("/listBlog") public String listBlog( @RequestParam(value = "page", required = false) String page, @RequestParam(value = "rows", required = false) String rows, Blog s_blog, HttpServletResponse response) throws Exception { PageBean<Blog> pageBean = new PageBean<Blog>(Integer.parseInt(page), Integer.parseInt(rows)); pageBean = blogService.listBlog(s_blog.getTitle(), pageBean); //创建json对象 JSONObject result = new JSONObject(); //设置json序列化日期格式 JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd"; //禁止对象循环引用 //使用默认日期格式化 String jsonStr = JSONObject.toJSONString(pageBean.getResult(), SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat); //得到json数组 JSONArray array = JSON.parseArray(jsonStr); //把结果放入json result.put("rows", array); result.put("total", pageBean.getTotal()); //返回 ResponseUtil.write(response, result); return null; } //更新或者新增博客 @RequestMapping(value = "/save") public String saveBlog(Blog blog,HttpServletResponse response) throws Exception { int resultTotal = 0; if(blog.getId()!=null){ //更新操作 resultTotal = blogService.updateBlog(blog); //更新索引 blogIndex.updateIndex(blog); }else{ //新增操作 resultTotal = blogService.saveBlog(blog); //添加索引 blogIndex.addIndex(blog); } JSONObject result = new JSONObject(); if(resultTotal > 0) { result.put("success", true); } else { result.put("success", false); } ResponseUtil.write(response, result); return null; } //删除博客 @RequestMapping(value = "delete") public String deleteBlog(@RequestParam("ids")String ids,HttpServletResponse response) throws Exception { String[] idsStr = ids.split(","); for(int i = 0; i < idsStr.length; i++) { int id = Integer.parseInt(idsStr[i]); //先删除博客所关联的评论 现在没有完成评论的功能 先注释 //commentService.deleteCommentByBlogId(id); blogService.deleteBlog(id); } JSONObject result = new JSONObject(); result.put("success", true); ResponseUtil.write(response, result); return null; } //通过id获取博客 @RequestMapping(value = "get") public String getById(@RequestParam("id") String id,HttpServletResponse response) throws Exception { Blog blog = blogService.getById(Integer.parseInt(id)); String jsonStr = JSONObject.toJSONString(blog); JSONObject result = JSONObject.parseObject(jsonStr); ResponseUtil.write(response, result); return null; } }
这里主要注意一下json序列化的时候
//设置json序列化日期格式
JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;
设置序列化时date序列化的格式
如果不设置 时间戳的格式,
设置完格式化日期格式后 就使用该格式序列化日期
还有一个问题就是对象循环引用的问题
什么是循环引用和重复引用
重复引用:一个对象中的多个属性同时引用同一个对象例如
Object obj=new Object(); Map<String,Object> map=new HashMap<>(); map.put("1", obj); map.put("2", obj);//引用了同一个对象 System.out.println(JSON.toJSONString(map));
循环引用:对象的属性之间存在相互引用导致循环,会引起StackOverFlow异常
例如:
Map<String,Object> map1=new HashMap<>(); Map<String,Object> map2=new HashMap<>(); map1.put("1",map2);//map1引用了map2 map2.put("1",map1);//map2又引用了map1,导致循环引用 System.out.println(JSON.toJSONString(map1));
fastjson支持循环引用/重复引用,并且是缺省打开的。
* 第一个例子序列化后输出结果为:{“1”:{},”2”:{“ref":".1”}}
第一个对象正常序列化,第二个对象则用引用表示
* 第二个列子序列化后输出结果为:{“1”:{“1”:{“$ref”:”..”}}}
关闭循环引用/重复引用
fastjson默认对json序列化的时候进行循环引用的检测,从而避免了出现StackOverFlow异常。当序列化后的JSON传输到浏览器或者其他语言中,这些json解析器不支持循环引用,从而导致数据丢失。你可以关闭fastjson的循环引用检测。全局配置关闭
``` 非全局关闭 ```java JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
当我们的博客属于同一个类型的时候 也就是说blogType属性相同的时候就会出现循环引用的情况 这样我们就需要关闭循环引用了。
这样控制层写完了
接下来我们可以使用postman测试了
下一节我们将实现博客的前台实现
相关文章推荐
- 【ssm个人博客项目实战06】博客类别的添加修改删除的实现
- 【ssm个人博客项目实战04】mybatis实现博客类别的增删改查分页
- 【ssm个人博客项目实战05】easy ui datagrid实现数据的分页显示
- 【ssm个人博客项目实战03】左侧导航菜单功能实现
- 【ssm个人博客项目实战09】写博客与自定义监听器
- 【ssm个人博客项目实战02】easy UI搭建后台管理界面
- [置顶] 【ssm个人博客项目实战01】SSM环境搭建
- 【ssm个人博客项目实战08】博客的分页显示以及模糊查询,删除。
- SSM个人博客项目实战01
- 个人博客系统--项目实战
- [thinkPHP5项目实战_07]引入后台管理页面
- 商城项目实战07:SSM框架整合之Service层整合
- ssm(springmvc4+spring4+mybatis3)整合实战-个人博客系统-前端页面的开发
- ssm(springmvc4+spring4+mybatis3)整合实战-个人博客系统-整合各大框架
- 基于ssm框架的个人博客系统(11)--后台开发及前后端数据交互
- Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录
- SSM个人博客系统搭建【一】:项目概述
- Python项目实战:个人博客(2):搭建orm框架
- Android 实战 - 个人APP乐逗项目(内部音乐播放器实现,开源MaskProgressView使用)