前言
完成了后台管理系统的页面设计之后,接下来是后台管理系统的后端代码编写。按照前端页面的设计,后台管理系统涉及到登录,分类、评论、文章管理,全文搜索等功能,按照从易到难的顺序,首先开发分类、评论、文章管理三个功能。还有一点就是,我给自己定下的开发原则是先实现,再求精,因为实际开发中总会遇到这样那样的细节问题,如果一直纠结于这些问题太影响开发效率了。
开发概述
开发顺序如下:
前后台数据交换格式统一为json。本篇文章先进行个人分类管理的开发。
个人分类管理
实体类,对照表设计:
package com.vansl.pojo;
/**
* @author: vansl
* @create: 18-4-12 下午4:45
*/
public class BlogType {
private Integer id; //分类ID
private String typeName; //分类名称
private Integer parentId; //父分类ID
private Integer userId; //用户ID
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public Integer getParentId() {
return parentId;
}
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
Dao接口,由于在applicationDao.xml配置文件里已经配置了MapperScannerConfigurer,所以会自动扫描并实例化:
package com.vansl.dao;
import com.vansl.entity.BlogType;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-12 下午5:14
*/
public interface BlogTypeDao {
// 通过id查询博客分类
BlogType selectById(Integer id);
// 通过用户id查询所有分类数据
List selectAll(Integer userId);
// 通过博客id查询博客分类
BlogType selectByBlogId(Integer blogId);
// 添加博客分类
Integer insertBlogType(BlogType blogType);
// 更新博客分类
Integer updateBlogType(BlogType blogType);
// 删除博客分类
Integer deleteBlogType(Integer id);
}
BlogTypeMapper.xml:
blog_type.id,blog_type.type_name,blog_type.parent_id,blog_type.user_id
INSERT INTO
blog_type(
type_name,
parent_id,
user_id
)
VALUES(
#{typeName},
#{parentId},
#{userId}
)
UPDATE
blog_type
SET
type_name=#{typeName}
WHERE
id=#{id}
DELETE FROM
blog_type
WHERE
id=#{id}
往表里插入一些数据然后写一个单元测试来测试一下Dao层:
package dao;
import com.vansl.dao.BlogTypeDao;
import com.vansl.entity.BlogType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-14 下午1:15
*/
@RunWith(SpringJUnit4ClassRunner.class)
// 加载spring配置文件
@ContextConfiguration({ "classpath:spring/applicationContext-dao.xml"})
public class BlogTypeDaoTest {
@Autowired
private BlogTypeDao blogTypeDao;
@Test
public void testSelectAll() throws Exception {
List result= blogTypeDao.selectAll("vansl");
for (BlogType blogType:result) {
System.out.println(blogType.getTypeName());
}
}
}
我是在idea下开发的,把mapper.xml文件放在java文件夹下会报错,解决方案参考这篇文章:解决 IDEA 中src下xml等资源文件无法读取的问题,推荐第二种方案。修复之后测试成功,说明Dao层没有问题。
package com.vansl.service.impl;
import com.vansl.dao.BlogTypeDao;
import com.vansl.dto.TypeTreeNode;
import com.vansl.entity.BlogType;
import com.vansl.service.BlogTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @author: vansl
* @create: 18-4-15 下午4:19
*/
@Service
public class BlogTypeServiceImpl implements BlogTypeService{
@Autowired
private BlogTypeDao blogTypeDao;
// 通过id查询博客分类
@Override
public TypeTreeNode selectById(Integer id) {
return getAncestors(id);
}
// 递归建立继承树
public TypeTreeNode getAncestors(Integer id) {
//把BlogType转换为TypeTreeNode以创建当前节点
TypeTreeNode son=new TypeTreeNode();
BlogType type=blogTypeDao.selectById(id);
son.setId(type.getId());
son.setText(type.getTypeName());
//如果是一级分类(id为0)则直接返回TypeTreeNode作为根节点
if(type.getParentId()==0){
return son;
//否则递归得到父节点
}else{
TypeTreeNode ansetor=getAncestors(type.getParentId());
//递归结束后把当前节点添加到父节点中作为子节点
//循环遍历树得到当前节点的父节点
TypeTreeNode father=ansetor;
while (father.getChildren()!=null){
father=father.getChildren().get(0);
}
List child=new ArrayList<>();
child.add(son);
father.setChildren(child);
//返回树
return ansetor;
}
}
// 返回某个用户的所有分类数据
@Override
public List selectAll(Integer userId) {
//查询结果
List typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap> map=new HashMap>();
//把blogType对象转换成TypeTreeNode对象并放入map
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList());
}
TypeTreeNode node=new TypeTreeNode();
node.setId(type.getId());
node.setText(type.getTypeName());
map.get(type.getParentId()).add(node);
}
//规定根结点id为0
TypeTreeNode root=new TypeTreeNode();
root.setId(0);
//递归添加子节点建立树
appendChildren(root,map);
//返回根结点的子节点
return root.getChildren();
}
// 递归建立树
public void appendChildren(TypeTreeNode node,HashMap> map){
//当子节点为空时放入一个空的List以保证JSON键的完整性,然后返回
if (map.get(node.getId())==null){
node.setChildren(new ArrayList<>());
return;
}
//设置子节点
node.setChildren(map.get(node.getId()));
//递归处理子节点
for (TypeTreeNode child:map.get(node.getId())) {
appendChildren(child,map);
}
}
// 通过博客id查询博客分类
@Override
public BlogType selectByBlogId(Integer blogId) {
return blogTypeDao.selectByBlogId(blogId);
}
// 添加博客分类
@Override
public Integer insertBlogType(BlogType blogType) {
if(blogType.getParentId()!=0){
BlogType father=blogTypeDao.selectById(blogType.getParentId());
if(father==null){
return -1;
// 限制最多只能有二级分类,以父分类id和parentId是否为0判断
}else if(father.getId()!=0&&father.getParentId()!=0){
return -1;
}
}
try{
blogTypeDao.insertBlogType(blogType);
}catch (Exception e){
//同个父分类下不允许有同名子分类
return 0;
}
return 1;
}
// 更新博客分类
@Override
public Integer updateBlogType(BlogType blogType) {
return blogTypeDao.updateBlogType(blogType);
}
// 删除博客分类
@Override
public Integer deleteBlogType(BlogType blogType) {
Integer id=blogType.getId();
Integer userId=blogType.getUserId();
//所有分类数据
List typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap> map=new HashMap>();
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList());
}
map.get(type.getParentId()).add(type);
}
//递归删除所有子类以及文章
return deleteChildren(id,map);
}
public Integer deleteChildren(Integer id,HashMap> map){
//递归处理子分类
if (map.get(id)!=null){
for (BlogType type:map.get(id)) {
Integer result=deleteChildren(type.getId(),map);
if(result==-1){
return -1;
}
}
}
//删除分类以及所属文章
try{
blogTypeDao.deleteBlogType(id);
//blogDao.deleteBlogByTypeId(id);
return 1;
}catch (Exception e){
e.printStackTrace();
return -1;
}
}
}
虽然限制分类最多只能有两级,我还是采用了map、递归等方法编写更一般的代码,注释比较详细。其中TypeTreeNode是一个用于前后端通讯的对象,新建一个dto包来存放:
package com.vansl.dto;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-15 下午5:54
*/
public class TypeTreeNode {
private Integer id;
private String text;
private List children;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public List getChildren() {
return children;
}
public void setChildren(List children) {
this.children = children;
}
}
接着也是向数据库中插入一些数据进行单元测试,代码如下 :
package service;
import com.vansl.entity.BlogType;
import com.vansl.service.BlogTypeService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
/**
* @author: vansl
* @create: 18-4-15 下午4:28
*/
@RunWith(SpringJUnit4ClassRunner.class)
// 加载spring配置文件
@ContextConfiguration({ "classpath:spring/applicationContext-dao.xml","classpath:spring/applicationContext-service.xml"})
public class BlogTypeServiceTest {
@Autowired
BlogTypeService blogTypeService;
@Test
public void testInsertBlogType() throws Exception {
BlogType type=new BlogType();
type.setUserId(1);
type.setParentId(0);
type.setTypeName("前端");
assertEquals(new Integer(1),blogTypeService.insertBlogType(type));
//同个父分类下不允许有同名子分类
assertEquals(new Integer(-1),blogTypeService.insertBlogType(type));
type.setParentId(1);
assertEquals(new Integer(1),blogTypeService.insertBlogType(type));
}
}
测试成功,说明service层也没有问题。
package com.vansl.controller;
import com.alibaba.fastjson.JSONObject;
import com.vansl.dto.TypeTreeNode;
import com.vansl.entity.BlogType;
import com.vansl.service.BlogTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-15 下午8:44
*/
@Controller
@RequestMapping("/type")
public class BlogTypeController {
@Autowired
BlogTypeService blogTypeService;
// 通过id查询博客分类
@GetMapping("/{id}")
@ResponseBody
public TypeTreeNode getTypeById(@PathVariable("id")Integer id){
return blogTypeService.selectById(id);
}
// 查询用户的所有分类数据
@GetMapping(params = {"userId"})
@ResponseBody
public List getAllData(@RequestParam("userId")Integer userId){
return blogTypeService.selectAll(userId);
}
// 通过博客id查询博客分类
@GetMapping(params = {"blogId"})
@ResponseBody
public BlogType getTypeByBlogId(@RequestParam("blogId")Integer blogId){
//调用service执行操作
return blogTypeService.selectByBlogId(blogId);
}
// 添加博客分类
@PostMapping
@ResponseBody
public String addBlogType(@RequestBody String data, HttpServletResponse response){
//把请求数据转换为JSON对象
JSONObject jsonObject = JSONObject.parseObject(data);
//从JSON对象中取出数据放入entity
BlogType type=new BlogType();
type.setTypeName((String)jsonObject.get("typeName"));
type.setParentId((Integer)jsonObject.get("parentId"));
Integer userId=(Integer)jsonObject.get("userId");
/*登录验证功能尚未实现*
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }else{
* type.setUserId(userId);
* }
*/
type.setUserId(userId);
//调用service执行操作
Integer result=blogTypeService.insertBlogType(type);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "class limited";
}else if(result==0){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
// 更新博客分类
@PutMapping
@ResponseBody
public String updateBlogType(@RequestBody String data, HttpServletResponse response){
//把请求数据转换为JSON对象
JSONObject jsonObject = JSONObject.parseObject(data);
//从JSON对象中取出数据放入entity
BlogType type=new BlogType();
type.setId((Integer)jsonObject.get("id"));
type.setTypeName((String)jsonObject.get("typeName"));
Integer userId=(Integer)jsonObject.get("userId");
/*登录验证功能尚未实现*
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }else{
* type.setUserId(userId);
* }
*/
type.setUserId(1);
//调用service执行操作
Integer result=blogTypeService.updateBlogType(type);
//操作失败返回则错误信息
if (result==0){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
// 删除博客分类
@DeleteMapping("/{id}")
@ResponseBody
public String deleteBlogType(@PathVariable("id")Integer id,@RequestBody String data, HttpServletResponse response){
//把请求数据转换为JSON对象
JSONObject jsonObject = JSONObject.parseObject(data);
//从JSON对象中取出数据放入entity
BlogType type=new BlogType();
type.setId(id);
/*登录验证功能尚未实现*
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }else{
* type.setUserId(userId);
* }
*/
type.setUserId(1);
//调用service执行操作
Integer result=blogTypeService.deleteBlogType(type);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
}
其中用户登录验证部分尚未完成,接着插入数据测试一下:
package controller;
import com.alibaba.fastjson.JSON;
import com.vansl.controller.BlogTypeController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
/**
* @author: vansl
* @create: 18-4-15 下午9:31
*/
@RunWith(SpringJUnit4ClassRunner.class)
// 加载spring配置文件
@ContextConfiguration({ "classpath:spring/applicationContext-dao.xml","classpath:spring/applicationContext-service.xml","classpath:spring/spring-mvc.xml"})
@WebAppConfiguration
public class BlogTypeControllerTest {
@Autowired
BlogTypeController blogTypeController;
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;
//初始化MockMvc对象
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
public void testDeleteBlogType() throws Exception {
Map
测试成功。分类管理部分的后端开发就完成了,然后修改一下前端代码的url部分,打开tomcat和浏览器测试一下,没有问题。
评论管理
实体类,对照表设计:
package com.vansl.entity;
import java.util.Date;
/**
* @author: vansl
* @create: 18-4-21 下午8:07
*/
public class BlogComment {
private Integer id; //评论ID
private Date time; //发表时间
private String name; //评论者
private String contact; //联系方式
private String ip; //评论者ip
private String address; //评论者地址
private String content; //评论内容
private Integer blogId; //博客ID
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getBlogId() {
return blogId;
}
public void setBlogId(Integer blogId) {
this.blogId = blogId;
}
}
Dao接口:
package com.vansl.dao;
import com.vansl.entity.BlogComment;
import java.util.List;
import java.util.Map;
/**
* @author: vansl
* @create: 18-4-21 下午9:00
*/
public interface BlogCommentDao {
// 通过用户id查询所有博客评论
List
相应的mapper.xml:
blog_comment.id,blog_comment.time,blog_comment.name,blog_comment.contact,
blog_comment.ip,blog_comment.address,blog_comment.content,blog_comment.blog_id
INSERT INTO
blog_comment(
blog_comment.name,
blog_comment.contact,
blog_comment.ip,
blog_comment.address,
blog_comment.content,
blog_comment.blog_id
)
VALUES(
#{name},
#{contact},
#{ip},
#{address},
#{content},
#{blogId}
)
DELETE FROM
blog_comment
WHERE
id=#{id}
DELETE FROM
blog_comment
WHERE
blog_id=#{blogId}
测试通过,测试代码略。
package com.vansl.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.vansl.dao.BlogCommentDao;
import com.vansl.dto.TableData;
import com.vansl.entity.BlogComment;
import com.vansl.service.BlogCommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* @author: vansl
* @create: 18-4-22 下午3:06
*/
@Service
public class BlogCommentServiceImpl implements BlogCommentService {
@Autowired
BlogCommentDao blogCommentDao;
@Override
public TableData selectAll(Integer userId, Integer offset, Integer limit) {
TableData result=new TableData();
// 分页并按照评论时间降序排列
PageHelper.startPage(offset, limit,"blog_comment.time DESC");
List
其中TableData是根据layui接口(参考:table模块/数据表格文档)用于封装表格数据的一个dto对象,之后博客管理部分也会用到,代码如下:
package com.vansl.dto;
import java.util.List;
import java.util.Map;
/**
* @author: vansl
* @create: 18-4-22 下午2:31
*/
// layui表格数据对象
public class TableData {
private Integer code; //成功的状态码,默认:0
private String msg; //状态信息
private Long count; //数据总数
private List> data; //数据
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Long getCount() {
return count;
}
public void setCount(Long count) {
this.count = count;
}
public List> getData() {
return data;
}
public void setData(List> data) {
this.data = data;
}
}
分页部分用到了PageHelper:MyBatis 分页插件 PageHelper,实现对sql无侵入式分页。
测试成功,测试代码略。
package com.vansl.controller;
import com.alibaba.fastjson.JSONObject;
import com.vansl.dto.TableData;
import com.vansl.utils.IPUtil;
import com.vansl.entity.BlogComment;
import com.vansl.service.BlogCommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-23 下午5:07
*/
@Controller
@RequestMapping("/comment")
public class BlogCommentController {
@Autowired
BlogCommentService blogCommentService;
// 查询用户的所有评论
@GetMapping(params = {"userId","offset","limit"})
@ResponseBody
public TableData getAllData(Integer userId, Integer offset, Integer limit){
/*登录验证功能尚未实现*
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
return blogCommentService.selectAll(userId,offset,limit);
}
// 通过博客id查询博客评论
@GetMapping(params = {"blogId","offset","limit"})
@ResponseBody
public List getByBlogId(Integer blogId, Integer offset, Integer limit){
List result=blogCommentService.selectByBlogId(blogId,offset,limit);
return result;
}
// 添加博客评论
@PostMapping
@ResponseBody
public String addBlogComment(@RequestBody BlogComment blogComment, HttpServletRequest request,HttpServletResponse response){
//获取并设置ip以及地址
String ip= IPUtil.getIp(request);
String address=IPUtil.getAddress(ip);
blogComment.setIp(ip);
blogComment.setAddress(address);
Integer result=blogCommentService.insertBlogComment(blogComment);
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
// 删除博客评论
@DeleteMapping("/{id}")
@ResponseBody
public String deleteBlogComment(@PathVariable("id")Integer id,@RequestBody String data,HttpServletResponse response ){
System.out.println("ssy");
// 把请求数据转换成请求对象
JSONObject json=JSONObject.parseObject(data);
Integer userId=(Integer) json.get("userId");
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
Integer result=blogCommentService.deleteBlogComment(id);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
}
其中添加评论时获取了前端的ip并查询ip对应地址然后入库,用到了IPUtil这个工具类,IPUtil又用到了HttpUtil这个工具类。HttpUtil的代码资料很多,实现也大同小异,这里不再给出。IPUtil代码如下,获取ip的方法参考他人博客:
package com.vansl.utils;
import com.alibaba.fastjson.JSON;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
/**
* @author: vansl
* @create: 18-4-24 下午7:04
*/
public class IPUtil {
public static String getIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
/*局域网无法获取公网ip,可使用http请求ip接口以获取
if(ip.equals("127.0.0.1")||ip.equals("0:0:0:0:0:0:0:1")){
//根据网卡取本机配置的IP
InetAddress inet=null;
try {
inet = InetAddress.getLocalHost();
} catch (Exception e) {
e.printStackTrace();
}
ip= inet.getHostAddress();
}
*/
}
// 多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(ip != null && ip.length() > 15){
if(ip.indexOf(",")>0){
ip = ip.substring(0,ip.indexOf(","));
}
}
if (ip.isEmpty()){
ip="未知";
}
return ip;
}
public static String getAddress(String ip){
String address=new String();
try {
//请求api获取地址
byte[] response= HttpUtil.doGet("http://ip.taobao.com/service/getIpInfo.php?ip="+ip);
//利用JSON转换unicode字符串
address=JSON.parseObject(new String(response)).toString();
}catch (Exception e){
e.printStackTrace();
}
return address;
}
测试成功。评论管理部分的后端开发完成,修改一下前端代码的url部分,打开浏览器测试,没有问题。
博客管理
实体类还是对照表设计,这里不再给出。
Dao接口:
package com.vansl.dao;
import com.vansl.dto.BlogData;
import com.vansl.entity.Blog;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-25 下午10:43
*/
public interface BlogDao {
// 通过用户id查询所有文章
List selectAll(@Param("published")Boolean published, @Param("userId")Integer userId);
// 通过博客id查询博客信息
BlogData selectById(Integer id);
// 通过分类id查询该分类下的所有博客
List selectByTypeId(@Param("published")Boolean published,@Param("typeIds")List typeIds);
// 通过博客id查询博客内容
String selectContentByBlogId(Integer id);
// 添加文章(包括草稿)
Integer insertBlog(Blog blog);
// 通过博客id更新博客字段
Integer updateBlog(Blog blog);
// 删除文章
Integer deleteBlog(Integer id);
// 通过分类id删除该分类下的所有文章
Integer deleteByTypeId(Integer typeId);
}
其中BlogData是一个dto对象,因为在查询文章列表时不需要text、content这两个字段,代码如下:
package com.vansl.dto;
import java.util.Date;
/**
* @author: vansl
* @create: 18-4-25 下午11:26
*/
public class BlogData {
private Integer id; //博客ID
private String title; //博客标题
private Date time; //发表时间
private Integer pv; //博客点击量
private Integer published; //博客是否已发表(0已发表,1未发表)
private Integer typeId; //博客分类id
private String typeName; //博客分类名称
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 Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public Integer getPv() {
return pv;
}
public void setPv(Integer pv) {
this.pv = pv;
}
public Integer getPublished() {
return published;
}
public void setPublished(Integer published) {
this.published= published;
}
public Integer getTypeId() {
return typeId;
}
public void setTypePId(Integer typeId) {
this.typeId = typeId;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
}
相应的mapper.xml:
INSERT INTO
blog(title,pv,content,text,published,user_id,type_id)
VALUES
(#{title},0,#{content},#{text},#{published},#{userId},#{typeId})
UPDATE
blog
title=#{title},
published=#{published},
content=#{content},
text=#{text},
type_id=#{typeId}
WHERE
id=#{id}
DELETE FROM
blog
WHERE
id=#{id}
DELETE FROM
blog
WHERE
type_id=#{type_id}
package com.vansl.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.vansl.dao.BlogDao;
import com.vansl.dao.BlogTypeDao;
import com.vansl.dto.BlogData;
import com.vansl.dto.TableData;
import com.vansl.entity.Blog;
import com.vansl.entity.BlogComment;
import com.vansl.entity.BlogType;
import com.vansl.service.BlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* @author: vansl
* @create: 18-4-25 下午11:29
*/
@Service
public class BlogServiceImpl implements BlogService {
@Autowired
BlogDao blogDao;
@Autowired
private BlogTypeDao blogTypeDao;
@Override
public TableData selectAll(Integer userId, Boolean published,Integer offset, Integer limit) {
TableData result=new TableData();
// 分页并按照上传时间降序排列
PageHelper.startPage(offset, limit,"blog.time DESC");
List data=blogDao.selectAll(published,userId);
result.setCode(0);
result.setMsg("ok");
PageInfo page = new PageInfo(data);
result.setCount(page.getTotal());
result.setData(data);
return result;
}
@Override
public BlogData selectById(Integer id) {
return blogDao.selectById(id);
}
@Override
public TableData selectByTypeId(Integer userId,Integer typeId,Boolean published,Integer offset, Integer limit){
//所有分类数据
List typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap> map=new HashMap>();
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList());
}
map.get(type.getParentId()).add(type.getId());
}
//保存所有子分类id
List typeIds=new ArrayList();
getChildrenId(typeId,map,typeIds);
TableData result=new TableData();
// 分页并按照上传时间降序排列
PageHelper.startPage(offset, limit,"blog.time DESC");
List data=blogDao.selectByTypeId(published,typeIds);
result.setCode(0);
result.setMsg("ok");
PageInfo page = new PageInfo(data);
result.setCount(page.getTotal());
result.setData(data);
return result;
}
public void getChildrenId(Integer typeId,HashMap> map,List typeIds){
//递归处理子分类
if (map.get(typeId)!=null){
for (Integer childId:map.get(typeId)) {
getChildrenId(childId,map,typeIds);
}
}
//删除分类以及所属文章
typeIds.add(typeId);
}
@Override
public Integer insertBlog(Blog blog) {
try {
Integer result=blogDao.insertBlog(blog);
return result;
}catch (Exception e){
e.printStackTrace();
return -1;
}
}
@Override
public String selectContentByBlogId(Integer id) {
return blogDao.selectContentByBlogId(id);
}
@Override
public Integer updateBlog(Blog blog) {
return blogDao.updateBlog(blog);
}
@Override
public Integer deleteBlog(Integer id) {
try {
Integer result=blogDao.deleteBlog(id);
return result;
}catch (Exception e){
e.printStackTrace();
return -1;
}
}
@Override
public Integer deleteByTypeId(Integer typeId) {
try {
Integer result=blogDao.deleteByTypeId(typeId);
return result;
}catch (Exception e){
e.printStackTrace();
return -1;
}
}
}
package com.vansl.controller;
import com.alibaba.fastjson.JSONObject;
import com.vansl.dto.TableData;
import com.vansl.entity.Blog;
import com.vansl.service.BlogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
/**
* @author: vansl
* @create: 18-4-27 下午2:25
*/
@Controller
@RequestMapping("/blog")
public class BlogController {
@Autowired
BlogService blogService;
// 查询用户的所有文章(包括草稿)
@GetMapping(params = {"userId","offset","limit"})
@ResponseBody
public TableData getAllData(Integer userId, Integer offset, Integer limit){
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
return blogService.selectAll(userId,false,offset,limit);
}
// 查询文章内容
@GetMapping("/{id}")
@ResponseBody
public String getContent(@PathVariable Integer id){
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
return blogService.selectContentByBlogId(id);
}
// 添加博客
@PostMapping
@ResponseBody
public String addBlog(@RequestBody Blog blog, HttpServletResponse response ){
Integer userId=blog.getUserId();
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
Integer result=blogService.insertBlog(blog);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
// 更新博客字段
@PutMapping("/{id}")
@ResponseBody
public String updateBlog(@PathVariable Integer id,@RequestBody Blog blog, HttpServletResponse response ){
Integer userId=blog.getUserId();
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
blog.setId(id);
Integer result=blogService.updateBlog(blog);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
// 删除博客
@DeleteMapping("/{id}")
@ResponseBody
public String deleteBlogComment(@PathVariable("id")Integer id, @RequestBody String data, HttpServletResponse response ){
// 把请求数据转换成请求对象
JSONObject json=JSONObject.parseObject(data);
Integer userId=(Integer) json.get("userId");
/*登录验证功能尚未实现
* Integer loginId=redisUtil.getUser().getUserId();
* if(loginId!=userId){
* return "denied";
* }
*/
Integer result=blogService.deleteBlog(id);
//操作失败返回则错误信息
if (result==-1){
response.setStatus(400);
return "error";
}else{
return "ok";
}
}
}
均测试成功。至此后端开发的第一部分:个人分类、评论、文章管理就完成了。