前言
完成了后台管理系统的页面设计之后,接下来是后台管理系统的后端代码编写。按照前端页面的设计,后台管理系统涉及到登录,分类、评论、文章管理,全文搜索等功能,按照从易到难的顺序,首先开发分类、评论、文章管理三个功能。还有一点就是,我给自己定下的开发原则是先实现,再求精,因为实际开发中总会遇到这样那样的细节问题,如果一直纠结于这些问题太影响开发效率了。
开发概述
开发顺序如下:
- 个人分类管理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<BlogType> selectAll(Integer userId);
// 通过博客id查询博客分类
BlogType selectByBlogId(Integer blogId);
// 添加博客分类
Integer insertBlogType(BlogType blogType);
// 更新博客分类
Integer updateBlogType(BlogType blogType);
// 删除博客分类
Integer deleteBlogType(Integer id);
}
BlogTypeMapper.xml:
<?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" >
<!-- Dao接口完全限定名 -->
<mapper namespace="com.vansl.dao.BlogTypeDao">
<!-- 结果集映射 -->
<resultMap id="BlogTypeResult" type="com.vansl.entity.BlogType">
<id property="id" column="id" />
<result property="typeName" column="type_name"/>
<result property="parentId" column="parent_id"/>
<result property="userId" column="user_id"/>
</resultMap>
<!-- 封装SQL语句 -->
<!-- blog_type表中基本字段 -->
<sql id="Base_Column_List" >
blog_type.id,blog_type.type_name,blog_type.parent_id,blog_type.user_id
</sql>
<!-- 通过id查询博客分类信息 -->
<!-- id为接口中的方法名 -->
<select id="selectById" resultMap="BlogTypeResult">
SELECT
<include refid="Base_Column_List"/>
FROM
blog_type
WHERE
id=#{id}
</select>
<!-- 通过userId查询所有分类数据 -->
<select id="selectAll" resultMap="BlogTypeResult">
SELECT
<include refid="Base_Column_List" />
FROM
blog_type
WHERE
user_id=#{userId}
</select>
<!-- 通过博客id查询博客分类 -->
<select id="selectByBlogId" resultMap="BlogTypeResult">
SELECT
<include refid="Base_Column_List" />
FROM
blog_type,blog
WHERE
blog_type.id=blog.type_id
AND
blog.id=#{blogId}
</select>
<!-- 添加博客分类 -->
<insert id="insertBlogType" parameterType="com.vansl.entity.BlogType" >
INSERT INTO
blog_type(
type_name,
parent_id,
user_id
)
VALUES(
#{typeName},
#{parentId},
#{userId}
)
</insert>
<!-- 更新博客分类 -->
<update id="updateBlogType" parameterType="com.vansl.entity.BlogType" >
UPDATE
blog_type
SET
type_name=#{typeName}
WHERE
id=#{id}
</update>
<!-- 删除博客分类 -->
<delete id="deleteBlogType">
DELETE FROM
blog_type
WHERE
id=#{id}
</delete>
</mapper>
往表里插入一些数据然后写一个单元测试来测试一下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<BlogType> 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<TypeTreeNode> child=new ArrayList<>();
child.add(son);
father.setChildren(child);
//返回树
return ansetor;
}
}
// 返回某个用户的所有分类数据
@Override
public List<TypeTreeNode> selectAll(Integer userId) {
//查询结果
List<BlogType> typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap<Integer,List<TypeTreeNode>> map=new HashMap<Integer,List<TypeTreeNode>>();
//把blogType对象转换成TypeTreeNode对象并放入map
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList<TypeTreeNode>());
}
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<Integer,List<TypeTreeNode>> 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<BlogType> typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap<Integer,List<BlogType>> map=new HashMap<Integer,List<BlogType>>();
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList<BlogType>());
}
map.get(type.getParentId()).add(type);
}
//递归删除所有子类以及文章
return deleteChildren(id,map);
}
public Integer deleteChildren(Integer id,HashMap<Integer,List<BlogType>> 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<TypeTreeNode> 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<TypeTreeNode> getChildren() {
return children;
}
public void setChildren(List<TypeTreeNode> 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<TypeTreeNode> 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<Object,Object> 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<Map> selectAll(Integer userId);
// 通过博客id查询博客评论
List<BlogComment> selectByBlogId(Integer blogId);
// 添加博客评论
Integer insertBlogComment(BlogComment blogComment);
// 删除博客评论
Integer deleteBlogComment(Integer id);
// 通过博客id删除博客评论
Integer deleteByBlogId(Integer blogId);
}
相应的mapper.xml:
<?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" >
<!-- Dao接口完全限定名 -->
<mapper namespace="com.vansl.dao.BlogCommentDao">
<!-- 结果集映射 -->
<resultMap id="BlogCommentResult" type="com.vansl.entity.BlogComment">
<id property="id" column="id" />
<result property="time" column="time"/>
<result property="name" column="name"/>
<result property="contact" column="contact"/>
<result property="ip" column="ip"/>
<result property="address" column="address"/>
<result property="content" column="content"/>
<result property="blogId" column="blog_id"/>
</resultMap>
<!-- 封装SQL语句 -->
<!-- blog_comment表中基本字段 -->
<sql id="Base_Column_List" >
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
</sql>
<!-- 通过用户id查询所有博客评论 -->
<!-- id为接口中的方法名 -->
<select id="selectAll" resultType="java.util.HashMap">
SELECT
<include refid="Base_Column_List"/>,blog.title
FROM
blog_comment,blog,user
WHERE
user.id=#{userId}
AND
blog_comment.blog_id=blog.id
AND
blog.user_id=user.Id
</select>
<!-- 通过博客id查询博客评论 -->
<select id="selectByBlogId" resultMap="BlogCommentResult">
SELECT
<include refid="Base_Column_List"/>
FROM
blog_comment,blog
WHERE
blog.id=#{blogId}
AND
blog_comment.blog_id=blog.id
</select>
<!-- 添加博客评论 -->
<insert id="insertBlogComment" parameterType="com.vansl.entity.BlogComment" >
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}
)
</insert>
<!-- 删除博客评论 -->
<delete id="deleteBlogComment">
DELETE FROM
blog_comment
WHERE
id=#{id}
</delete>
<!-- 通过博客id删除博客评论 -->
<delete id="deleteByBlogId">
DELETE FROM
blog_comment
WHERE
blog_id=#{blogId}
</delete>
</mapper>
测试通过,测试代码略。
- 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<Map> 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<BlogComment> 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<BlogComment> getByBlogId(Integer blogId, Integer offset, Integer limit){
List<BlogComment> 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<BlogData> selectAll(@Param("published")Boolean published, @Param("userId")Integer userId);
// 通过博客id查询博客信息
BlogData selectById(Integer id);
// 通过分类id查询该分类下的所有博客
List<BlogData> selectByTypeId(@Param("published")Boolean published,@Param("typeIds")List<Integer> 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:
<?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" >
<!-- Dao接口完全限定名 -->
<mapper namespace="com.vansl.dao.BlogDao">
<!-- 结果集映射 -->
<resultMap id="BlogDataResult" type="com.vansl.dto.BlogData">
<id property="id" column="id" />
<result property="title" column="title"/>
<result property="time" column="time"/>
<result property="pv" column="pv"/>
<result property="published" column="published"/>
<result property="typeId" column="type_id"/>
<result property="typeName" column="type_name"/>
</resultMap>
<!-- 通过用户id查询所有文章 -->
<!-- id为接口中的方法名 -->
<select id="selectAll" resultMap="BlogDataResult">
SELECT
blog.id,
blog.title,
blog.time,
blog.pv,
blog.published,
blog.type_id,
blog_type.type_name
FROM
blog,blog_type
WHERE
blog.type_id=blog_type.id
AND
blog.user_id=#{userId}
<if test="published">
AND
blog.published=0
</if>
</select>
<!-- 通过博客id查询博客信息 -->
<select id="selectById" resultMap="BlogDataResult">
SELECT
blog.id,
blog.title,
blog.time,
blog.pv,
blog.published,
blog.type_id,
blog_type.type_name
FROM
blog,blog_type
WHERE
blog.type_id=blog_type.id
AND
blog.id=#{id}
</select>
<!-- 通过分类id查询该分类下的所有博客 -->
<select id="selectByTypeId" resultMap="BlogDataResult">
SELECT
blog.id,
blog.title,
blog.time,
blog.pv,
blog.published,
blog.type_id
FROM
blog,blog_type
WHERE
blog.type_id=blog_type.id
AND
blog_type.id
IN
<foreach item="item" index="index" collection="typeIds"
open="(" separator="," close=")">
#{item}
</foreach>
<if test="published">
AND
blog.published=0
</if>
</select>
<!-- 更新博客分类 -->
<select id="selectContentByBlogId" resultType="java.lang.String">
SELECT
content
FROM
blog
WHERE
id=#{id}
</select>
<!-- 更新博客分类 -->
<insert id="insertBlog" parameterType="com.vansl.entity.Blog" >
INSERT INTO
blog(title,pv,content,text,published,user_id,type_id)
VALUES
(#{title},0,#{content},#{text},#{published},#{userId},#{typeId})
</insert>
<!-- 更新博客 -->
<update id="updateBlog" parameterType="com.vansl.entity.Blog" >
UPDATE
blog
<!-- set用于去除多于逗号-->
<set>
<if test="title != null">title=#{title},</if>
<if test="published != null">published=#{published},</if>
<if test="content != null">content=#{content},</if>
<if test="text != null">text=#{text},</if>
<if test="typeId != null">type_id=#{typeId}</if>
</set>
WHERE
id=#{id}
</update>
<!-- 删除博客 -->
<delete id="deleteBlog">
DELETE FROM
blog
WHERE
id=#{id}
</delete>
<!-- 通过分类id删除该分类下的所有博客 -->
<delete id="deleteByTypeId">
DELETE FROM
blog
WHERE
type_id=#{type_id}
</delete>
</mapper>
- 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<BlogData> 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<BlogType> typeList=blogTypeDao.selectAll(userId);
//以parentId为索引建立map以查找子分类
HashMap<Integer,List<Integer>> map=new HashMap<Integer,List<Integer>>();
for (BlogType type:typeList) {
if (map.get(type.getParentId())==null){
map.put(type.getParentId(),new ArrayList<Integer>());
}
map.get(type.getParentId()).add(type.getId());
}
//保存所有子分类id
List<Integer> typeIds=new ArrayList<Integer>();
getChildrenId(typeId,map,typeIds);
TableData result=new TableData();
// 分页并按照上传时间降序排列
PageHelper.startPage(offset, limit,"blog.time DESC");
List<BlogData> 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<Integer,List<Integer>> map,List<Integer> 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";
}
}
}
均测试成功。至此后端开发的第一部分:个人分类、评论、文章管理就完成了。