【实战】6-2 分类管理开发

前言

商品分类模块给它设计的接口暂时不多,这一章节也比较简单,除了一个递归获取所有子节点的接口外~
接下来就一个一个文件的放出来,大家直接参考和看代码中的注释就好了。

controller设计

这里在controller/backend包下创建CategoryManageController.java,专门用来控制对商品分类的操作。
功能大部分还是在service中实现的,这里主要是把session中的相关信息拿出来,并做一些简单的判断,如是否登录,是否是管理员等。
注意使用了一个新的注解@RequestParam(value = “parentId”,defaultValue = “0”)可以实现不传参数情况下的默认参数(感觉这些注解实现了很强大的功能,有时间要好好了解一下具体的实现原理)。

package top.winxblast.happymall.controller.backend;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import top.winxblast.happymall.common.Const;
import top.winxblast.happymall.common.ResponseCode;
import top.winxblast.happymall.common.ServerResponse;
import top.winxblast.happymall.pojo.User;
import top.winxblast.happymall.service.CategoryService;
import top.winxblast.happymall.service.UserService;

import javax.servlet.http.HttpSession;

/**
 * 目录管理模块
 *
 * @author winxblast
 * @create 2017/10/28
 **/
@Controller
@RequestMapping(value = "/manage/category")
public class CategoryManageController {

    @Autowired
    private UserService userService;

    @Autowired
    private CategoryService categoryService;

    /**
     * 添加商品类别
     * 添加这个注解@RequestParam(value = "parentId",defaultValue = "0")主要是为了没有传这个参数时有个默认值。
     * @param session 通过session验证用户是否已登录以及是否为管理员
     * @param categoryName
     * @param parentId
     * @return
     */
    @RequestMapping(value = "add_category.do", method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> addCategory(HttpSession session, String categoryName, @RequestParam(value = "parentId",defaultValue = "0") int parentId) {
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if(user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录");
        }

        //校验是否为管理员,功能放到service中
        if(userService.checkAdminRole(user).isSuccess()) {
            //是管理员
            //增加处理分类的逻辑
            return categoryService.addCategory(categoryName, parentId);
        } else {
            return ServerResponse.createByErrorMessage("无权限,需要管理员权限");
        }
    }

    /**
     * 修改品类名称
     * @param session
     * @param categoryId
     * @param categoryName
     * @return
     */
    @RequestMapping(value = "set_category_name.do", method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> setCategoryName(HttpSession session, Integer categoryId, String categoryName) {
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if(user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录");
        }

        //校验是否为管理员,功能放到service中
        if(userService.checkAdminRole(user).isSuccess()) {
            //是管理员
            //更新categoryName
            return categoryService.updateCategoryName(categoryId, categoryName);
        }else {
            return ServerResponse.createByErrorMessage("无权限,需要管理员权限");
        }
    }

    /**
     * 通过父类id获取下一级子分类
     * @param session
     * @param categoryId 不传参数默认为0
     * @return
     */
    @RequestMapping(value = "get_category.do", method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse getChildrenParallelCategory(HttpSession session, @RequestParam(value = "categoryId", defaultValue = "0")Integer categoryId) {
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if(user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录");
        }

        //校验管理员
        if(userService.checkAdminRole(user).isSuccess()) {
            //查询子节点的category信息,并且不递归,只查询下一级
            return categoryService.getChildrenParallelCategory(categoryId);
        } else {
            return ServerResponse.createByErrorMessage("无权限,需要管理员权限");
        }
    }

    /**
     * 通过递归查询该分类下所有子分类
     * 这个方法的名字取的我也是醉了···最讨厌取名字了,这里老师取名感觉也是随意
     * @param session
     * @param categoryId 不传参数默认为0
     * @return
     */
    @RequestMapping(value = "get_deep_category.do", method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse getCategoryAndDeepChildrenCategory(HttpSession session, @RequestParam(value = "categoryId", defaultValue = "0")Integer categoryId) {
        User user = (User)session.getAttribute(Const.CURRENT_USER);
        if(user == null) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(), "用户未登录,请登录");
        }

        //校验管理员
        if(userService.checkAdminRole(user).isSuccess()) {
            //查询当前节点及递归子节点的id
            return categoryService.selectCategoryAndChildrenById(categoryId);
        } else {
            return ServerResponse.createByErrorMessage("无权限,需要管理员权限");
        }
    }
}

service设计

先给出接口的定义把CategoryService。后来我按照阿里巴巴Java规约的一些习惯把接口命名前面的大写“I”去掉了,直接使用xxService,然后在实现类后面加上Impl。

package top.winxblast.happymall.service;

import top.winxblast.happymall.common.ServerResponse;
import top.winxblast.happymall.pojo.Category;

import java.util.List;

/**
 * 分类操作模块接口
 *
 * @author winxblast
 * @create 2017/10/28
 **/
public interface CategoryService {

    ServerResponse<String> addCategory(String categoryName, Integer parentId);

    ServerResponse<String> updateCategoryName(Integer categoryId, String categoryName);

    ServerResponse<List<Category>> getChildrenParallelCategory(Integer categoryId);

    ServerResponse selectCategoryAndChildrenById(Integer categoryId);

}

然后是接口的实现类。这里混用了google的guava和Apache的commons,网上讨论也比较多,暂时还没有精力去分辨那个好,这里就先按老师写的混用着。
至于以后工作中那就看同事用什么就用什么啦

package top.winxblast.happymall.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.winxblast.happymall.common.ServerResponse;
import top.winxblast.happymall.dao.CategoryMapper;
import top.winxblast.happymall.pojo.Category;
import top.winxblast.happymall.service.CategoryService;

import java.util.List;
import java.util.Set;

/**
 * 分类模块接口实现类
 *
 * @author winxblast
 * @create 2017/10/28
 **/
@Service("categoryService")
public class CategoryServiceImpl implements CategoryService {

    private Logger logger = LoggerFactory.getLogger(CategoryServiceImpl.class);

    @Autowired
    private CategoryMapper categoryMapper;

    /**
     * 添加品类
     * @param categoryName 品类名称
     * @param parentId 父品类id,SpringMVC中默认使用0,如果没有传入
     * @return
     */
    @Override
    public ServerResponse<String> addCategory(String categoryName, Integer parentId) {
        if(parentId == null || StringUtils.isBlank(categoryName)) {
            return ServerResponse.createByErrorMessage("添加品类参数错误");
        }

        Category category = new Category();
        category.setName(categoryName);
        category.setParentId(parentId);
        category.setStatus(true);//表示这个分类是可用的,有效的

        int rowCount = categoryMapper.insert(category);
        if(rowCount > 0) {
            return ServerResponse.createBySuccessMessage("添加品类成功");
        }
        return ServerResponse.createByErrorMessage("添加品类失败");
    }

    /**
     * 修改品类名字
     * @param categoryId
     * @param categoryName
     * @return
     */
    @Override
    public ServerResponse<String> updateCategoryName(Integer categoryId, String categoryName) {
        if(categoryId == null || StringUtils.isBlank(categoryName)) {
            return ServerResponse.createByErrorMessage("更新品类参数错误");
        }

        Category category = new Category();
        category.setId(categoryId);
        category.setName(categoryName);

        int rowCount = categoryMapper.updateByPrimaryKeySelective(category);
        if(rowCount > 0) {
            return ServerResponse.createBySuccessMessage("更改品类名字成功");
        }
        return ServerResponse.createByErrorMessage("更改品类名字失败");
    }

    /**
     * 仅获取下一级分类
     * @param categoryId
     * @return
     */
    @Override
    public ServerResponse<List<Category>> getChildrenParallelCategory(Integer categoryId) {
        List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
        if(CollectionUtils.isEmpty(categoryList)) {
            //这里没有子分类为什么打印日志比较好呢,应该可以有其他处理方法,这里按照老师的讲解来
            logger.info("未找到当前分类的子分类");
        }
        return ServerResponse.createBySuccess(categoryList);
    }

    /**
     * 递归查询本节点id和孩子节点id
     * 和下面一个private方法联合使用
     * @param categoryId
     * @return
     */
    @Override
    public ServerResponse selectCategoryAndChildrenById(Integer categoryId) {
        //这个跟我平时不一样,用的谷歌的一个包来初始化,里面也有很多方便的工具
        Set<Category> categorySet = Sets.newHashSet();
        findChildCatgory(categorySet,categoryId);

        //同样是谷歌guava里的方法
        List<Integer> categoryIdList = Lists.newArrayList();
        if(categoryId != null) {
            for (Category categoryItem : categorySet) {
                categoryIdList.add(categoryItem.getId());
            }
        }
        return ServerResponse.createBySuccess(categoryIdList);
    }
    /**
     * 这里要重写Category的hashcode和equals方法
     * 递归算法算出子节点
     */
    private Set<Category> findChildCatgory(Set<Category> categorySet, Integer categoryId) {
        Category category = categoryMapper.selectByPrimaryKey(categoryId);
        if(category != null) {
            categorySet.add(category);
        }

        //查找子节点,递归算法一定要有停止条件
        List<Category> categoryList = categoryMapper.selectCategoryChildrenByParentId(categoryId);
        //由于mybatis的设计,如果没有查询结果,也不会返回null,所以下面不用进行null判断
        for (Category categoryItem : categoryList) {
            findChildCatgory(categorySet, categoryItem.getId());
        }
        return categorySet;
    }
}

注意这里重写了category的hashcode和equals方法,因为要把按我们想要的方式放进hashset中。这两个方法的重写直接使用idea提供的方法就可以了。

dao层

对于数据库的操作,在mybatis generator的基础上,自己就添加了一个方法,以下为相关接口及xml配置内容,我自己添加的内容在两个文件的最后部分。

CategoryMapper.java

package top.winxblast.happymall.dao;

import top.winxblast.happymall.pojo.Category;

import java.util.List;

public interface CategoryMapper {
    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    int deleteByPrimaryKey(Integer id);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    int insert(Category record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    int insertSelective(Category record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    Category selectByPrimaryKey(Integer id);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    int updateByPrimaryKeySelective(Category record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table happymall_category
     *
     * @mbggenerated Sun Oct 08 14:03:47 CST 2017
     */
    int updateByPrimaryKey(Category record);

    /**
     * 通过父类Id查看下一级子分类的情况
     * @param parentId
     * @return
     */
    List<Category> selectCategoryChildrenByParentId(Integer parentId);
}

CategoryMapper.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" >
<mapper namespace="top.winxblast.happymall.dao.CategoryMapper" >
  <resultMap id="BaseResultMap" type="top.winxblast.happymall.pojo.Category" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    <constructor >
      <idArg column="id" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="parent_id" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="name" jdbcType="VARCHAR" javaType="java.lang.String" />
      <arg column="status" jdbcType="BIT" javaType="java.lang.Boolean" />
      <arg column="sort_order" jdbcType="INTEGER" javaType="java.lang.Integer" />
      <arg column="create_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
      <arg column="update_time" jdbcType="TIMESTAMP" javaType="java.util.Date" />
    </constructor>
  </resultMap>
  <sql id="Base_Column_List" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    id, parent_id, name, status, sort_order, create_time, update_time
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    select 
    <include refid="Base_Column_List" />
    from happymall_category
    where id = #{id,jdbcType=INTEGER}
  </select>

  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    delete from happymall_category
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="top.winxblast.happymall.pojo.Category" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    insert into happymall_category (id, parent_id, name, 
      status, sort_order, create_time, 
      update_time)
    values (#{id,jdbcType=INTEGER}, #{parentId,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, 
      #{status,jdbcType=BIT}, #{sortOrder,jdbcType=INTEGER}, now(),
      now())
  </insert>
  <insert id="insertSelective" parameterType="top.winxblast.happymall.pojo.Category" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    insert into happymall_category
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="parentId != null" >
        parent_id,
      </if>
      <if test="name != null" >
        name,
      </if>
      <if test="status != null" >
        status,
      </if>
      <if test="sortOrder != null" >
        sort_order,
      </if>
      <if test="createTime != null" >
        create_time,
      </if>
      <if test="updateTime != null" >
        update_time,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="parentId != null" >
        #{parentId,jdbcType=INTEGER},
      </if>
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="status != null" >
        #{status,jdbcType=BIT},
      </if>
      <if test="sortOrder != null" >
        #{sortOrder,jdbcType=INTEGER},
      </if>
      <if test="createTime != null" >
        now(),
      </if>
      <if test="updateTime != null" >
        now(),
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="top.winxblast.happymall.pojo.Category" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    update happymall_category
    <set >
      <if test="parentId != null" >
        parent_id = #{parentId,jdbcType=INTEGER},
      </if>
      <if test="name != null" >
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="status != null" >
        status = #{status,jdbcType=BIT},
      </if>
      <if test="sortOrder != null" >
        sort_order = #{sortOrder,jdbcType=INTEGER},
      </if>
      <if test="createTime != null" >
        create_time = #{createTime,jdbcType=TIMESTAMP},
      </if>
      <if test="updateTime != null" >
        now(),
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="top.winxblast.happymall.pojo.Category" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Oct 08 14:03:47 CST 2017.
    -->
    update happymall_category
    set parent_id = #{parentId,jdbcType=INTEGER},
      name = #{name,jdbcType=VARCHAR},
      status = #{status,jdbcType=BIT},
      sort_order = #{sortOrder,jdbcType=INTEGER},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      update_time = now()
    where id = #{id,jdbcType=INTEGER}
  </update>

  <select id="selectCategoryChildrenByParentId" resultMap="BaseResultMap" parameterType="int">
    SELECT
    <include refid="Base_Column_List"/>
    FROM happymall_category
    WHERE parent_id = #{parentId}
  </select>
</mapper>

接口测试

还是继续使用我们的chrome插件restlet client,这里我就上几张图给大家参考一下就好了,还是比较容易使用的,不过测试要尽可能覆盖一些特殊情况,虽然我们不是专业的测试,但是也要考虑的周到一些。
这次的4个接口都是使用GET方法就可以了,带默认参数的可以试试不传入参数。
get_category.do接口
这里写图片描述
这里写图片描述

add_category.do
这里写图片描述

set_category_name.do
这里写图片描述

get_deep_category.do
这里写图片描述

同时由于是使用GET方法提交参数,我们也不需要写HTML表单,可以直接在浏览器中输入相应的地址来查看返回值,这里json格式化的效果是由插件FE助手完成的,大家要是使用火狐浏览器的话可以浏览器直接支持格式化json的。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值