(一)案例介绍 
   我在开发一个权限管理系统,里面涉及到为“用户组”分配可操作“菜单项”,这里面的两个实体“用户组”和“菜单项”就是多对多的关系:一个用户组可以分配多个菜单项,一个菜单项可以分配给多个用户组。 
 (二)表设计 
   1.用户组
CREATE TABLE `sys_group` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '组名',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;2.菜单项
CREATE TABLE `sys_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(50) DEFAULT NULL COMMENT '组名',
  `url` varchar(200) DEFAULT NULL COMMENT '访问地址',
  `parent_id` int(11) DEFAULT NULL COMMENT '父菜单ID',
  `order_num` int(2) DEFAULT NULL COMMENT '排序数字',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;3.为用户组分配菜单项表
CREATE TABLE `sys_group_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `group_id` int(11) DEFAULT NULL COMMENT '组id',
  `menu_id` int(11) DEFAULT NULL COMMENT '菜单id',
  PRIMARY KEY (`id`),
  KEY `fk_sys_group_idx` (`group_id`),
  KEY `fk_sys_menu_idx` (`menu_id`),
  CONSTRAINT `fk_sys_group` FOREIGN KEY (`group_id`) REFERENCES `sys_group` (`id`),
  CONSTRAINT `fk_sys_menu` FOREIGN KEY (`menu_id`) REFERENCES `sys_menu` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;备注:对于对多对关系,我们一般选择冗余一张表,来建立两个实体之间的关系!
(三)Java对象 
   1.用户组(Group)
package com.imooc.bean;
import java.util.List;
/**
 * @author 咸鱼
 * @date 2018/6/18 17:45
 */
public class Group extends BaseBean {
    /**
     * 用户组名称
     */
    private String name;
    /**
     * 一对多关系映射(Group和Menu并不直接产生联系,而是靠中间表产生联系)
     */
    private List<Menu> menuList;
}2.菜单项(Menu)
package com.imooc.bean;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.util.List;
/**
 * @author 咸鱼
 * @date 2018/6/20 7:37
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Menu extends BaseBean {
    /**
     * 菜单名称
     */
    private String name;
    private String url;
    private Integer parentId;
    /**
     * 排序权重
     */
    private Integer orderNum;
    /**
     * 一对多关系映射(Group和Menu并不直接产生联系,而是靠中间表产生联系)
     */
    private List<Group> groupList;
}(四)Mybtis映射文件(我们以查询“用户组”为例)
<resultMap id="GroupMap" type="Group">
        <id column="g_id" property="id"/>
        <result column="g_name" property="name"/>
        <!-- 1对多映射 -->
        <collection property="menuList" ofType="Menu">
            <id column="m_id" property="id"/>
            <result column="m_name" property="name"/>
            <result column="m_url" property="url"/>
            <result column="m_parent_id" property="parentId"/>
            <result column="m_order_num" property="orderNum"/>
        </collection>
    </resultMap>(五)具体的查询sql语句(我们以查询“用户组”为例)
<select id="selectGroups" parameterType="Group" resultMap="GroupMap">
        SELECT g.id g_id,g.name g_name,m.id m_id,m.name m_name,m.url m_url,m.parent_id m_parent_id,m.order_num m_order_num
        FROM sys_group g
        LEFT JOIN sys_group_menu gm ON g.id=gm.group_id
        LEFT JOIN sys_menu m ON m.id=gm.menu_id
        <where>
            <if test="id != null">AND g.id=#{id}</if>
            <if test="name != null and !"".equals(name.trim())">AND g.`name`=#{name}</if>
        </where>
        ORDER BY CONVERT(g.`name` using gbk) COLLATE gbk_chinese_ci
    </select>(六)易错点 
   1.在配置映射表的时候,Group会有一个id,Menu也会有一个id,若我们在配置映射表时,对“column”属性不加以区分,那么Mybatis不知道将查询到的id放到哪里(因为它是根据别名来将值放到对应的属性的)。解决办法:将“column”配置成不同的别名,然后在查询的时候,将对应的字段后面放上别名即可! 
   2.sql语句的返回类型一定要配置成映射表!!!(在这里我错了好多次),若不配置成这样,那么出来的结果,集合成员变量肯定为null。 
   3.这里为了保证用户组不管分配没分配菜单都能被查询出来,所以,使用的是“LEFT JOIN”,具体和“=”的区别,参见我另外一篇七、“where g.id=m.id”与“LEFT JOIN sys_menu m ON g.id=m.id”区别?
                
                










