SpringBoot +MyBatis 两表关联嵌套查询

本文详细介绍了如何使用SpringBoot和MyBatis进行两表关联嵌套查询,通过具体代码示例展示了从数据库表设计到查询结果返回的全过程,包括CityDto和AppDto的数据封装、Mapper接口定义、Mapper.xml配置以及Service和Controller的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot +MyBatis 两表关联嵌套查询

废话不多说,代码走起来!

效果图

{
    "respCode": "200",
    "respMessage": "成功",
    "data": [
        {
            "cityId": 11,
            "cityName": "河南",
            "appDto": [
                {
                    "appId": 1,
                    "appName": "城市之窗",
                    "province": 11
                },
                {
                    "appId": 2,
                    "appName": "政务通",
                    "province": 11
                },
                {
                    "appId": 3,
                    "appName": "南阳通",
                    "province": 11
                },
                {
                    "appId": 4,
                    "appName": "洛阳通",
                    "province": 11
                }
            ]
        },
        {
            "cityId": 12,
            "cityName": "黑龙江",
            "appDto": [
                {
                    "appId": 5,
                    "appName": "黑龙江通",
                    "province": 12
                }
            ]
        },
        {
            "cityId": 20,
            "cityName": "宁夏",
            "appDto": [
                {
                    "appId": 6,
                    "appName": "宁夏通",
                    "province": 20
                }
            ]
        },
        {
            "cityId": 17,
            "cityName": "江西",
            "appDto": [
                {
                    "appId": 7,
                    "appName": "江西通",
                    "province": 17
                }
            ]
        }
    ]
}

数据库表

sport_contro_app表和sport_contro_city表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for sport_contro_app
-- ----------------------------
DROP TABLE IF EXISTS `sport_contro_app`;
CREATE TABLE `sport_contro_app` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'APP id',
  `name` varchar(32) NOT NULL COMMENT 'app名称',
  `province` bigint(11) NOT NULL COMMENT '所属省份编号 0 河南省',
  `version` varchar(50) NOT NULL COMMENT '版本',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'APP详情记录创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '该条记录修改时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for sport_contro_city
-- ----------------------------
DROP TABLE IF EXISTS `sport_contro_city`;
CREATE TABLE `sport_contro_city` (
  `id` int(5) unsigned NOT NULL AUTO_INCREMENT COMMENT '省市级联id',
  `parent_id` int(5) unsigned NOT NULL DEFAULT '0' COMMENT '归属省份编号',
  `name` varchar(120) NOT NULL COMMENT '城市名称',
  `type` int(1) NOT NULL DEFAULT '2' COMMENT '类型(0为国家1省份直辖市 特别行政区 2地级市3地级区县)',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3410 DEFAULT CHARSET=utf8;

封装的CityDto

import lombok.Data;

import java.io.Serializable;
import java.util.List;

@Data
public class CityDto implements Serializable {
    /**
     *  省市级联id
     */
    private  long cityId;
    /**
     *  城市名称
     */
    private String cityName;
    /**
     *  app集合
     */
    private List<AppDto> appDto;
}

封装的AppDto

import lombok.Data;

import java.io.Serializable;

@Data
public class AppDto implements Serializable {
    /**
     * app id
     * */
    private long appId;
    /**
     * App名称
     * */
    private String appName;
    /**
     * 所属省份编号
     * */
    private long province;
}

Mapper接口

 /**
     * 查询城市和app接口
     * @param
     * @return
     */
    List<CityDto> findAllCityAndApp();

Mapper.xml 文件

<resultMap id="CityAndApp" type="com.deyi.sponsor.pojo.dto.CityDto">
		<id column="city_id" property="cityId" jdbcType="BIGINT" />
		<result column="city_name" property="cityName" jdbcType="VARCHAR"/>
		<collection property="appDto" ofType="com.deyi.sponsor.pojo.dto.AppDto">
			<id column="id" property="appId" jdbcType="BIGINT" />
			<result column="name" property="appName" jdbcType="VARCHAR" />
			<result column="province" property="province" jdbcType="BIGINT" />
		</collection>
	</resultMap>
	
	<select id="findAllCityAndApp" resultMap="CityAndApp">
		SELECT
			city.id as city_id,
			city.name as city_name,
			app.province,
			app.id,
			app.name
		FROM
			sport_contro_app app
		LEFT JOIN sport_contro_city city ON app.province = city.id
	</select>

Service接口

/**
     * 查询城市和app接口
     * @param
     * @return
     */
    OutputObject findAllCityAndApp();

ServiceImpl实现类

 /**
     * 查询城市和app接口
     * @param
     * @return
     */
    @Override
    public OutputObject findAllCityAndApp(){
        List<CityDto> list = sportPlanMapper.findAllCityAndApp();
        return new OutputObject(StatusCodeEnum.SUCCESS.getCode(), StatusCodeEnum.SUCCESS.getMessage(), list);
    }

Controller控制器

 /**
     * 查询城市和app接口
     * @param
     * @return
     */
    @PostMapping("/allCityAndApp/find")
    public OutputObject findAllCityAndApp(){
        return sportPlanService.findAllCityAndApp();
    }

大功告成!!!

SpringBoot_Freemarker生成Word_+层嵌套循环; 步骤说明: 1.用Microsoft Office Word打开word原件;将文档中需要动态生成的内容,替换为属性名 ${name} 2.另存为,选择保存类型Word 2003 XML 文档(*.xml) 3.用Firstobject free XML editor打开文件,选择Tools下的Indent【或者按快捷键F8】格式化文件内容。左边是文档结构,右边是文档内容; 4. 文档生成后有时需要手动修改,查找第一步中设置的属性名,可能会产生类似${n.....ame}类似的样子,我们将将名字中间的标签删掉,恢复为${name} 5. word模板中有格,需要循环的位置, 用 标签将第二对 标签(即除头的w:tr标签后的一对)包围起来 同时格内的属性例如${name},在这里需要修改为${user.name} (userList是集合在dataMap中的key, user是集合中的每个元素, 类似), 如图: PLUS:若格之外还有嵌套的循环,也需要用,注意这里的标签不要和某对其他标签交叉,不可以出现这种 6. 标识替换完之后,另存为.ftl后缀文件即可。 代码里是相对有一丢丢复杂的,层嵌套循环; 总(dataMap) deptName 部门名 list(Table)的集合 table1(map) table-名字 ${map.table} tableName-中文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段中文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--格2 map.listB …… listC-List--格3 map.listC …… table2 table-名字 ${map.table} tableName-中文名 ${map.tableName} columnCount-字段数 ${map.columnCount} recordCount-记录数 ${map.recordCount} listA-List--格1 map.listA column Model属性——字段名 ${model.column} columnName Model属性——字段中文名 ${model.column} rate Model属性——字段占比 ${model.rate} nullValueCount Model属性——字段空值数 ${model.nullValueCount} listB-List--格2 map.listB …… listC-List--格3 map.listC …… table3 ……
### Spring Boot 中使用 MyBatis 进行单查询 #### 单查询实现 为了在 Spring Boot 项目中执行单查询,首先需要设置好基础环境并编写相应的 Mapper 接口以及对应的 XML 文件来定义 SQL 映射。 创建一个简单的 `User` 实体类用于示用户信息: ```java public class User { private Long id; private String name; private Integer age; // Getters and Setters... } ``` 接着,在 `mapper` 包下建立名为 `UserMapper.java` 的接口文件,其中声明了基本 CRUD 方法: ```java @Mapper public interface UserMapper { List<User> selectAllUsers(); int insertUser(User user); Optional<User> findById(Long userId); boolean updateUser(User user); void deleteUserById(Long userId); } ``` 对于上述方法的具体 SQL 语句,则可以在同目录下的 `UserMapper.xml` 定义[^2]: ```xml <mapper namespace="com.example.demo.mapper.UserMapper"> <!-- Select all users --> <select id="selectAllUsers" resultType="com.example.demo.model.User"> SELECT * FROM t_user ORDER BY id ASC </select> <!-- Insert a new record into the database table --> <insert id="insertUser" parameterType="com.example.demo.model.User" useGeneratedKeys="true" keyProperty="id"> INSERT INTO t_user (name, age) VALUES(#{name}, #{age}) </insert> </mapper> ``` #### 关联查询实践 当涉及到格之间的关系处理时,比如一对的关系,可以通过嵌套结果映射的方式完成复杂的数据检索操作。假设存在个实体——订单 (`Order`) 和 订单项(`OrderItem`) ,它们之间是一对的关系。 先看 `Order` 类结构: ```java public class Order { private Long orderId; private Date orderDate; private Customer customer; private List<OrderItem> items = Lists.newArrayList(); // Getter & Setter ... } ``` 再来看 `OrderItem` : ```java public class OrderItem { private Long itemId; private Product product; private BigDecimal quantity; private BigDecimal price; // Getter & Setter ... } ``` 针对这个模型设计的联合查询逻辑可放在 `OrderMapper.java` 中: ```java @Mapper public interface OrderMapper { /** * Fetch orders along with their associated items. */ List<Order> findOrdersWithItems(@Param("customerId")Long customerId); } ``` 配合着下面这段 XML 来描述具体的 SQL 行为: ```xml <select id="findOrdersWithItems" resultMap="orderResultMap"> SELECT o.*, oi.* FROM tb_order AS o JOIN tb_order_item as oi ON o.order_id=oi.order_id WHERE o.customer_id=#{customerId}; </select> <resultMap type="com.example.Order" id="orderResultMap"> <collection property="items" ofType="com.example.OrderItem" column="{orderId=o.order_id}"> <id property="itemId"/> <association property="product" javaType="Product"> <constructor> <arg column="item_product_name" /> <arg column="item_price" /> </constructor> </association> <result property="quantity" column="item_quantity"/> <result property="price" column="item_unit_price"/> </collection> </resultMap> ``` 此段代码展示了如何通过 `<resultMap>` 标签指定复杂的属性映射规则,并利用 `<collection>` 子标签指明集合类型的成员变量应该如何填充数据;而 `<association>` 则用来指示一对一关联的对象初始化方式[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值