Spring项目准备

十四.项目前奏

14.1整合加上传下载

14.1.1 修改之前的上传代码

package com.aaa.controller;

import com.aaa.pojo.User;
import com.aaa.service.UserService;
import com.aaa.service.UserServiceImpl;
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.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

/**
 * Created by 张晨光 on 2020/7/31 15:19
 * 控制器Controller,作用和之前的Servlet一样;
 */
@Controller
public class FileController {
    //仍然使用依赖注入,来调用业务层对象的;
    //证明这个时候注入不成功;
    @Resource(name = "userService")
    UserService userService;

    @RequestMapping("/upload")
    public String upload(User user,MultipartFile fileImg,HttpServletRequest request) throws IOException {
        //d://aaa/idea/.../upload
        String path=request.getServletContext().getRealPath("/upload");
        String fileName=fileImg.getOriginalFilename();
        String ext=fileName.substring(fileName.lastIndexOf("."));
        fileName=UUID.randomUUID().toString()+ext;
        //上传的时候用到什么????
        //IO流:InputStream/OutputStream;  Reader/Writer
        //第二个参数有文件名;
        File file=new File(path,fileName);
        //如果file不存在,或者
        if(!file.exists()||!file.isDirectory())
        {
            file.mkdirs();//创建目录和子目录
        }
        //这时候,已经确定了目录;
        fileImg.transferTo(file);
        //设置用户的图片,是fileName
        user.setImg(fileName);
        userService.saveUser(user);
        //完毕之后去了一个hello页面,要查询所有用户信息
        //return "hello";
        return "forward:user/getUsers";
    }
}

14.1.2 UserController

更改如下,之前的无用代码都删除掉

@Controller
@RequestMapping("/user")
public class UserController {
    //调用业务层对象;\
    @Autowired
    UserService userService;

    @RequestMapping("/getUsers")
    public String getUsers(Model model){
        //业务层对象,查询用户信息
        List<User> userList = userService.selectAllUsers();
        model.addAttribute("userList",userList);
        //将来要去View-》JSP页面
        return "userlist";
    }
}

14.1.3 Model层代码

UserDao

public interface UserDao {
    //增加用户信息
    void saveUser(User user);
    //用户编辑
    void updateUser(User user);
    void delUser(int id);//根据id来删除用户
    User findUserById(int id);//根据id来查询用户操作;
    //要再次做下查询所有用户信息
    List<User> selectAllUsers();
}

UserDaoImpl,注意写增加代码和查询所有代码即可,如果有了,不用动

@Repository("userDao")
public class UserDaoImpl implements UserDao {
    //使用自动注入,来调用Spring容器提供的JdbcTemplate这个Bean
    @Resource(name = "jdbcTemplate")
    JdbcTemplate jdbcTemplate;

    public void saveUser(User user) {
        String sql="insert user(name,img)values(?,?)";
        Object[]params={user.getName(),user.getImg()};
        System.out.println("正式用户");
        jdbcTemplate.update(sql,params);
    }
    public void updateUser(User user) {
        String sql="update user set pwd=? where id=?"; //有?了这么办?
        int result=jdbcTemplate.update(sql,user.getPwd(),user.getId());//Object...params
        if(result>0)
            System.out.println("更新成功");
        else
            System.out.println("更新失败!");
    }
    public void delUser(int id) {
        System.out.println("模拟根据id来实现删除用户");
    }
    public User findUserById(int id) {
        System.out.println("根据id来查询单一用户信息");
        return null;
    }
    //dao层实现类的获取;查询的是单表数据 ;
    public List<User> selectAllUsers() {
        String sql="select * from user ";
        //String sql="select * from user where gender=? and ";
        //query查询方法的参数:sql
        //固定的格式:BeanPropertyRowMapper<待查询的类名>(待查询类.class)  适用于单一类;
        //原理:就是通过User.class这个字节码文件,利用反射机制,来读取里面的元数据信息
        //获取查询列表的,使用List<User>
        List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class), null);
        //List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class), "男");
        return userList;
    }
}

UserService

public interface UserService {
    //增加用户信息,业务
    void saveUser(User user);
    void updateUser(User user);
    void delUser(int id);//根据id来删除用户
    User findUserById(int id);//根据id来查询用户操作;
    //查询所有用户信息
    List<User> selectAllUsers();
}

UserServiceImpl,只写增加和查询的,其他不用管

@Service("userService")
public class UserServiceImpl implements UserService{
    //业务层实现类,调用dao对象;
    //UserDao userDao=new UserDaoImpl();利用Spring容器来解耦,它来直接托管Bean的创建
    @Resource(name="userDao") //必须有name=
    UserDao userDao;
    //下面这些代码和之前javaweb分层的代码一模一样
    public void saveUser(User user) {
        userDao.saveUser(user);
    }
    public void updateUser(User user) {
        userDao.updateUser(user);
    }
    public void delUser(int id) {
        userDao.delUser(id);
    }
    public User findUserById(int id) {
        return userDao.findUserById(id);
    }    //
    public List<User> selectAllUsers() {
        return userDao.selectAllUsers();
    }
}

userlist.jsp代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
    <style>
        table,td{
            border: 1px solid #f00;border-collapse: collapse;
            text-align: center;
        }
        img{width:80px;height: 60px;}
    </style>
</head>
<body>
    Userlist列表信息展示<br/>
    <table>
        <tr>
            <td>编号</td>
            <td>姓名</td>
            <td>图片</td>
            <td>操作</td>
        </tr>
        <%--tr嵌套到forEach 里面--%>
        <c:forEach items="${userList}" var="user">
            <tr>
                <td>${user.id}</td>
                <td> ${user.name}</td>
                <td><img src="/upload/${user.img}"/></td>
                <td>编辑|删除</td>
            </tr>
        </c:forEach>
    </table>

</body>
</html>

效果:

image-20200803154034880.png

13.1.4 下载

springmvc提供的ResponseEntity类型,使用它可以很方便地定义返回的HttpHeaders和HttpStatus

在userList.jsp下增加下载的文件

<a rel="nofollow" href="/download?fileName=${user.img}">下载</a>

方式一:在FileController下增加代码

@RequestMapping("/download")
    public ResponseEntity<byte[]> export(String fileName,String filePath,HttpServletRequest request) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        filePath=request.getServletContext().getRealPath("/upload");
        File file = new File(filePath+"/"+fileName);

        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", fileName);

        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    }

方式二:稍微复杂一点的,这个代码多,但是更好理解。

知识点:response,响应对象;

ServletOutpuStream 输出字节流

@RequestMapping("/download2")
    public String download( String fileName ,String filePath, HttpServletRequest request, HttpServletResponse response)
    {
        try {
            //获取页面输出流
            ServletOutputStream outputStream = response.getOutputStream();
            filePath=request.getServletContext().getRealPath("/upload");
            File file = new File(filePath+"/"+fileName);
            byte[] bytes = FileUtils.readFileToByteArray(file); //把文件以二进制形式写回
            //向输出流写文件
            //写之前设置响应流以附件的形式打开返回值,这样可以保证前边打开文件出错时异常可以返回给前台
            response.setHeader("Content-Disposition","attachment;filename="+fileName);
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
            return "success";
        } catch (IOException e) {
            e.printStackTrace();
            return "error";
        }
    }

下载效果如下:

image-20200804180419546.png

14.2 整合加日期类型

数据

image-20200801143252955.png

image-20200801143230806.png

该问题一般是:

1.实体类属性和数据库、页面不一致引起;

2.前端提交的内容在后端一般都用String类型来接收,用Date类型接收会报错。

3.controller代码方法中使用了@RequestParam注解,但是在jsp中没有对应的@RequestParam注解name属性参数值,而且@RequestParam注解的required属性默认为true,也就是说,jsp中参数值必须对应@RequestParam注解的name属性值。

解决日期类型的几种方法

注意:2020/01/01,这种方式的时候,不会报错;报错的格式是2020-01-01,-,.包括年月日 ,都会出错;

14.2.1 实体类修改

在日期变量处直接添加@DateTimeFormat(pattern="yyyy-MM-dd")

14.2.2 Controller修改

image-20200805122940122.png

@InitBinder
public void initBinder(WebDataBinder binder) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
    dateFormat.setLenient(false);
    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    //true:允许输入空值,false:不能为空值
}

如果这里面,日期格式:课程的图片上传,LessonController,user图标上传,UserController,部门创建日期,deptController,

Score,class,Grade,很多个Controller都涉及到日期,我们是不是需要在这么多的。Controller都加上上面的这段代码。

image-20200806102104399.png

14.2.3自定义类型转换器

我们在使用SpringMVC时,常常需要把表单中的参数映射到我们对象的属性中,我们可以在默认的spring-servlet.xml加上如下的配置即可做到普通数据类型的转换,如将String转换成Integer和Double等:对于日期来说,Spring支持的格式是2019/11/11,当我们传入2019-11-11,程序会报错,这时候就需要我们自定义类型转换器来满足我们的需要。

使用详细步骤:

1.Convert接口

public interface Converter<S, T> {
    //S:来源,String类型
    //T:目标,Target
    @Nullable
    T convert(S var1);
}

2.自定义类型实现类

public class DateConvert implements Converter<String, Date> {
    @Override
    public Date convert(String value) {
        SimpleDateFormat sdf=null;
        //参考一下即可;
        if(value==null)
            throw new RuntimeException("日期不能为空");
        else if(value.contains("年"))
            sdf =new SimpleDateFormat("yyyy年mm月dd日");
        else if(value.contains("-"))
            sdf=new SimpleDateFormat("yyyy-mm-dd");
        else if(value.contains("."))
            sdf=new SimpleDateFormat("yyyy.mm.dd");
        //将日期转换一下;
        try {
            return sdf.parse(value);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

3.配置springmvc

<!--3.配置自定义类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <!--增加自定义的类型转换器 -->
            <bean class="com.aaa.utils.DateConvert"/>
        </set>
    </property>
</bean>
<mvc:annotation-driven conversion-service="conversionService"/>

dao层对象,sql代码更改

public void saveUser(User user) {
    //把之前没有的日期sql代码增加过来过去.
    String sql="insert user(name,img,birth)values(?,?,?)";
    Object[]params={user.getName(),user.getImg(),user.getBirth()};
    jdbcTemplate.update(sql,params);
}

第三种的好处,是适用于全局项目,大家练习的时候,直接第三种。

14.3异常

简单异常信息处理:

14.3.1 假设Controller信息报错如何办?500如何办?

@Controller
public class ExpController {
    @RequestMapping("/exp")
    public String exp(){
        //异常:
        System.out.println(10/0); //除0错;
        return "hello";
    }
}

14.3.2 在SpringMVC.xml下增加如下配置

最简单的配置.复制粘贴.

 <!--自定义异常视图处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--默认页面处理代码-->
        <property name="defaultErrorView" value="error"/>
        <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->
        <property name="exceptionAttribute" value="ex"></property>
    </bean>

14.3.3

错误信息页面处理

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--可以使用el表达式,否则el表达式起不到作用;--%>
<html>
<head>
    <title>Title</title>
</head>
<body>
    error
    <img src="/static/img/500.png"/>
    <%--输出刚才的那个异常的属性,ex;--%>
    <c:out value="${ex}"></c:out>
</body>
</html>

总结:

1.整合上传下载

2.日期增加

3.统一异常类型处理

扩展实现

<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.Exception">errors/error</prop>
            <prop key="java.lang.Throwable">errors/err</prop>
        </props>
    </property>
    <property name="statusCodes">
        <props>
            <prop key="errors/error">500</prop>
            <prop key="404">404</prop>
        </props>
    </property>
    <!-- 设置日志输出级别,不定义则默认不输出警告等错误日志信息 -->
    <property name="warnLogCategory" value="WARN"></property>
    <!-- 默认错误页面,当找不到上面mappings中指定的异常对应视图时,使用本默认配置 -->
    <property name="defaultErrorView" value="errors/error"></property>
    <!-- 默认HTTP状态码 -->
    <property name="defaultStatusCode" value="500"></property>
</bean>

十五.项目分页

分页是项目中非常重要的一个功能实现,实现方式有多种。

image-20200806212153057.png

这是一个分页导航,其中能够得到的数据有

pageNo: 当前页数

pageSize: 一页显示多少条记录

countPages: 一共多少页

countRows: 一共多少条

//mysql-->分页

pageList: 数据集合,List类型

业务流程图:

image-20200810153431491.png

分页步骤如下:

1.定义pageBean类

作为存储分页数据的Bean

package com.aaa.utils;
import java.util.List;
/**
 * Created by 张晨光 on 2020/8/6 21:14
 */
public class PageBean {
    private int pageNo;     //当前页码
    private int pageSize=3;       //一页显示多少条记录
    private int countPages;     //总共多少页
    private int countRows;      //公共多少条记录
    private List pageList;      //查询的记录集合

    public int getPageNo() {
        return pageNo;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getCountPages() {
        return countPages;
    }

    public void setCountPages(int countPages) {
        this.countPages = countPages;
    }

    public int getCountRows() {
        return countRows;
    }

    public void setCountRows(int countRows) {
        this.countRows = countRows;
    }

    public List getPageList() {
        return pageList;
    }

    public void setPageList(List pageList) {
        this.pageList = pageList;
    }
}

2.pageUtil类,通用查询分页类

代替了之前在很多个Servlet里面,写的一堆代码,BookServlet,ProducetServlet,OrderServlet,

提取公共的代码,封装一下。

作用: 获取分页数据

1.作用查询总条数

2.获取总页数

3.查询分页后数据集合

问题1:拼接字符串

问题2:mysql分页如何写

package com.aaa.utils;

import com.aaa.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * Created by 张晨光 on 2020/8/6 21:43
 */
@Component
public class PageUtils {
    @Resource(name = "jdbcTemplate")
    JdbcTemplate jdbcTemplate;
    public void selectPage(String sql,PageBean page){
        //1.查询总条数
        StringBuffer stringBuffer=new StringBuffer("select count(*) countRows from( ");
        stringBuffer.append(sql);
        stringBuffer.append(") a");
        //获取数据库中的总条数;
       //注意:这个使用的是查询单列的聚合数据        
        Integer countRows = jdbcTemplate.queryForObject(sb1.toString(),Integer.class);;
        
        //1.2.将总条数放入pageBean中
        page.setCountRows(countRows);
        //2.计算总页数;
        int countPages=0;
        countPages=countRows%page.getPageSize()==0?(countRows/page.getPageSize()):(countRows/page.getPageSize()+1);
        //将总页数存入pageBean
        page.setCountPages(countPages);
        //3.查询分页的集合;
        StringBuffer sb=new StringBuffer(sql);
        sb.append(" limit ");
        sb.append((page.getPageNo()-1)*page.getPageSize());
        sb.append(",");
        sb.append(page.getPageSize());
        //这个在输入查询的sb.toString(),切记别写错;
        List<User> userList = jdbcTemplate.query(sb.toString(), new BeanPropertyRowMapper<User>(User.class));
        page.setPageList(userList);
    }
}

3.dao层

3.1 UserDao接口
//查询用户数量数量;
    void selectAllUsers(PageBean page);
3.2UserDaoImpl实现类

注意,需要在这里使用pageUtil的注解实现

@Override
    public void selectAllUsers(PageBean page) {
        String sql="select * from user";
        pageUtils.selectPage(sql,page);
    }

4.Service层

4.1UserService接口
 //查询用户数量数量;
    void selectAllUsers(PageBean page);
4.2UserServiceImpl实现类
 @Override
    public void selectAllUsers(PageBean page) {
        userDao.selectAllUsers(page);
    }

5.Controller类

控制层的分页:

package com.aaa.controller;

import com.aaa.pojo.User;
import com.aaa.service.UserService;
import com.aaa.utils.PageBean;
import com.mysql.cj.xdevapi.SchemaImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created by 张晨光 on 2020/7/27 14:25
 * 类前也可以加@RequestMapping:请求映射注解,窄化处理,实际上就是对控制器可以分类;
 */
@Controller
@RequestMapping("/user")
public class UserController {
    //调用业务层对象;\
    @Autowired
    UserService userService;
    //第二种方式,增加一个WebDataBinder;
    //这个注解的作用,增加一个初始化的数据绑定功能; 只要来调用Controller,就初始化绑定
    //这个还是有一定的问题;
    /*@InitBinder
    public void initBinder(WebDataBinder webDataBinder){
        //这个是指定按照我们的日期 时间格式;
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
        sdf.setLenient(false);
        //WebDataBinder:页面数据绑定类,注册一个自定义的绑定功能;
        //将Date.class这个日期类,和刚才的SimpleDateFormat的对象做下绑定
        webDataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sdf,true));
    }*/

    @RequestMapping("/getUsers")
    public String getUsers(Model model){
        //业务层对象,查询用户信息
        List<User> userList = userService.selectAllUsers();
        model.addAttribute("userList",userList);
        //将来要去View-》JSP页面
        return "userlist";
    }
    @RequestMapping("/regUser")
    public String regUser(User user, MultipartFile fileImg, HttpServletRequest request){
        //之前的代码省略
        return "";
    }
    @RequestMapping("/toUserList")
    public String toUserList(HttpServletRequest request,HttpServletResponse response){
        int pageNo=1;
        //接受从前台传递过来的数据,如果不为空,则传递过去;否则是第一页;
        if(request.getParameter("pageNo")!=null){
            pageNo=Integer.parseInt(request.getParameter("pageNo"));
        }
        //初始化,分页Bean
        PageBean page=new PageBean();
        page.setPageNo(pageNo);
        //查询数据库,并将查到的数据,提取到PageBean里面
        userService.selectAllUsers(page);
        //传递值;
        request.setAttribute("page",page);
//        System.out.println(page.getPageList());
        return "forward:getUsers";
    }
}

6.View层页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isELIgnored="false" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/login.css"/>
    <script src="/static/js/jquery-2.1.0.min.js"></script>
    <script>
        function goPage(pageNo) {
            location.href='toUserList?pageNo='+pageNo;
        }
    </script>
</head>
<body>
    Userlist列表信息展示<br/>
    <table>
        <tr>
            <td>编号</td>
            <td>姓名</td>
            <td>图片</td>
            <td>操作</td>
        </tr>
        <%--tr嵌套到forEach 里面--%>
        <c:forEach items="${page.pageList}" var="user">
            <tr>
                <td>${user.id}</td>
                <td> ${user.name}</td>
                <td><img src="/upload/${user.img}"/>
                    <%--<a rel="nofollow" href="${pageContext.request.contextPath}/upload/${user.img}">下载</a>--%>
                    <%--/:下载的图片链接--%>
                    <a rel="nofollow" href="/download?fileName=${user.img}">下载</a>
                </td>
                <td>编辑|删除</td>
            </tr>
        </c:forEach>
        <tr>
            <td colspan="4">
                <a rel="nofollow" href="#" onclick="goPage(1)">首页</a>
                <c:if test="${page.pageNo<1}">
                    <a rel="nofollow" href="#">上一页</a>
                </c:if>
                <c:if test="${page.pageNo>1}">
                    <a rel="nofollow" href="#" onclick="goPage(${page.pageNo-1})">上一页</a>
                </c:if>
                <c:if test="${page.pageNo<page.countPages}">
                    <a rel="nofollow" href="#" onclick="goPage(${page.pageNo+1})">下一页</a>
                </c:if>
                <a rel="nofollow" href="#" onclick="goPage(${page.countPages})">尾页</a>
                当前第${page.pageNo}页/共${page.countPages}页
            </td>
        </tr>
    </table>

</body>
</html>

7.效果

image-20200807002204519.png

十六.权限思路

RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

授权实际上是WhoWhatHow 三元组之间的关系,也就是WhoWhat 进行How 的操作,也就是“主体”对“客体”的操作。

Who:是权限的拥有者或主体(如:User,Role)。

What:是操作或对象(operation,object)。

How:具体的权限(Privilege,正向授权与负向授权)。

一、权限系统

这一天将讲述一个基本的基于数据库的权限管理系统的设计,在这一天的课程的最后将讲述“左右值无限分类实现算法”如何来优化“系统菜单”的结构而告终。今天的内容和前几天的基础框架是一样的它们都属于基础知识,在这些基础知识上还可以扩展出无数的变种与进化设计。

二、先来看客户的一个需求

2.1 用户实际需求

背景需求:

需要在“权限”=>“角色”=>“用户”之间,在赋予一个特殊的角色“客服”,这个需求比较常见,我一个用户想把我的权限分配到“客服”角色上,然后由几个“客服”去操作对应的业务流程。比如我们的天猫,淘宝商家后天就是如此,当店铺开到一定的规模,那么就会有分工。

A客服:负责打单填写发货单。

B~E客服:负责每天对我们说“亲,您好。祝亲生活愉快!”,也就是和我们沟通交流的客服。

F~H:负责售后。

... ...

那么这些客服也是归属到这个商家下面去。而且每个商家可能都有类似的客服,分工完全靠商家自己去分配管理。