从简到繁——SSM个人博客搭建完全记录【3】后台管理系统的后端开发之一(分类、评论、文章管理)

前言

  完成了后台管理系统的页面设计之后,接下来是后台管理系统的后端代码编写。按照前端页面的设计,后台管理系统涉及到登录,分类、评论、文章管理,全文搜索等功能,按照从易到难的顺序,首先开发分类、评论、文章管理三个功能。还有一点就是,我给自己定下的开发原则是先实现,再求精,因为实际开发中总会遇到这样那样的细节问题,如果一直纠结于这些问题太影响开发效率了。

开发概述

 开发顺序如下:

  • 个人分类管理Dao层、Service层、Controller层
  • 评论管理Dao层、Service层、Controller层,分页处理
  • 文章管理Dao层、Service层、Controller层,分页处理

  前后台数据交换格式统一为json。本篇文章先进行个人分类管理的开发。

个人分类管理

  •   Dao层

实体类,对照表设计:

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层没有问题。

  • service层(实现类)
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层也没有问题。

  • Controller层
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 map=new HashMap<>();
        map.put("userId",1);
        String data= JSON.toJSONString(map);
        String result= mockMvc.perform(delete("/type/242").
                contentType(MediaType.APPLICATION_JSON).content(data)).
                andDo(print()).
                andReturn().
                getResponse().
                getContentAsString();
        System.out.println(result);
    }
}

测试成功。分类管理部分的后端开发就完成了,然后修改一下前端代码的url部分,打开tomcat和浏览器测试一下,没有问题。

评论管理

  • Dao层

实体类,对照表设计:

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 selectAll(Integer userId);

    // 通过博客id查询博客评论
    List selectByBlogId(Integer blogId);

    // 添加博客评论
    Integer insertBlogComment(BlogComment blogComment);

    // 删除博客评论
    Integer deleteBlogComment(Integer id);

    // 通过博客id删除博客评论
    Integer deleteByBlogId(Integer blogId);
}

相应的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}
  

测试通过,测试代码略。

  • Service层
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 data=blogCommentDao.selectAll(userId);
        result.setCode(0);
        result.setMsg("ok");
        PageInfo page = new PageInfo(data);
        result.setCount(page.getTotal());
        result.setData(data);
        return result;
    }

    @Override
    public List selectByBlogId(Integer blogId,Integer offset,Integer limit) {
        // 分页并按照评论时间降序排列
        PageHelper.startPage(offset, limit,"blog_comment.time DESC");
        return blogCommentDao.selectByBlogId(blogId);
    }

    @Override
    public Integer insertBlogComment(BlogComment blogComment) {
        try {
            Integer result=blogCommentDao.insertBlogComment(blogComment);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    @Override
    public Integer deleteBlogComment(Integer id) {
        try {
            Integer result=blogCommentDao.deleteBlogComment(id);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }

    @Override
    public Integer deleteByBlogId(Integer blogId) {
        try {
            Integer result=blogCommentDao.deleteByBlogId(blogId);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            return -1;
        }
    }
}

其中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无侵入式分页。

测试成功,测试代码略。

  • Controller层
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层

实体类还是对照表设计,这里不再给出。

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}
  

  • Service层
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;
        }
    }


}

  • Controller层
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";
        }
    }


}

均测试成功。至此后端开发的第一部分:个人分类、评论、文章管理就完成了。

你可能感兴趣的:(SSM)