本文介绍了Spring Boot中使用MybatisPlus进行多表查询的方法,包括一对多、多对一关系的实现,以及条件查询和分页查询的示例。

初学Spring boot

MybatisPlus多表查询

这个学的有点绕,下面我来仔细地捋一捋。

实现一对多

查询某用户的信息及所有订单

首先,在User实体中加入一个List类型的orders,并标明该字段在表中并不存在,不要忘记给这个orders生成getter和setter方法。

    // 描述用户的所有订单
    @TableField(exist = false)
    private List<Order> orders;
  • User实体映射到数据库中表的规则

默认映射规则

MyBatis-Plus 默认的 实体类名到表名映射规则:

驼峰转下划线(CamelCase → snake_case)

去掉前缀(如果有的话,可自定义)

例子:

实体类名    数据库表名默认映射
User    user
OrderItem    order_item
ProductCategory    product_category

所以如果表名就是 user,类名就是 User,完全匹配,就不需要 @TableName。

如果表明和实体名不一致,则需要在实体定义前边加上 @TableName("t_user"),意思是该类去对应数据库中的 't_user'表


@TableName("t_user")
public class User {
}

然后,在UserMapper中加入该方法的映射关系

    //查询用户及其所有订单
    @Select("select * from t_user")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "password",property = "password"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "id",property = "orders",javaType = List.class,
                many = @Many(select = "org.example.mpdemo.mapper.OrderMapper.selectByUid")
            )
    })
    List<User> selectAllUserAndOrders();
  • 一个小知识点,Mapper是interface,也就是接口,可以继承BaseMapper(这个BaseMapper里有许多内置的方法),在UserController这个拦截器里边,可以直接标注@AutoWired,相当于交给Spring容器,自动根据这个userMapper接口生成了一个实例,可以直接调用这个接口里的方法
@Autowired
    private UserMapper usermapper;

最后,可以在UserController中调用这个一对多的多表查询了

    @GetMapping("/user/findAll")
    public List<User> find() {
        return usermapper.selectAllUserAndOrders();
    }

实现多对一

基本方法和原理同一对多的多表查询

OrderMapper中的映射写法

    // 查询所有的订单,同时查询订单的用户
    @Select("select * from t_order")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "order_time",property = "order_time"),
            @Result(column = "total",property = "total"),
            @Result(column = "uid",property = "user",javaType = User.class,
                one = @One(select = "org.example.mpdemo.controller.UserController.selectById")
            )
    })
    List<Order> selectAllOrdersAndUser();

条件查询

    // 条件查询
    @GetMapping("/user/find")
    public List<User> findByCond() {
        QueryWrapper<User> queryWrapper = new QueryWrapper();
        queryWrapper.eq("username","zhangsan");
        return usermapper.selectList(queryWrapper);
    }

分页查询

要先在config中加一个拦截器

package org.example.mpdemo.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfig
{
    public MybatisPlusInterceptor paginationInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        interceptor.addInnerInterceptor(paginationInterceptor);
        return interceptor;
    }
}
    // 分页查询 select * from xx limit 0,10
    @GetMapping("/user/findByPage")
    public IPage findByPage() {
        //设置起始值及每页条数
        Page<User> page = new Page(0,2);
        IPage iPage = usermapper.selectPage(page,null);
        return iPage;
    }

Cors 跨域问题

  • 为了保证浏览器的安全,不同源的客户端脚本在没有明确授权的情况下,不能
    读写对方资源,称为同源策略,同源策略是浏览器安全的基石
  • 同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安
    全功能
  • 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主
    机(host)和端口号(port)
  • 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨
    域,此时无法读取非同源网页的 Cookie,无法向非同源地址发送 AJAX 请求

跨域问题解决

  • CORS(Cross-Origin Resource Sharing)是由W3C制定的一种跨域资源共享
    技术标准,其目的就是为了解决前端的跨域请求。
  • CORS可以在不破坏即有规则的情况下,通过后端服务器实现CORS接口,从而
    实现跨域通信。
  • CORS将请求分为两类:简单请求和非简单请求,分别对跨域通信提供了支持。

简单请求的服务器处理

  • 对于简单请求,CORS的策略是请求时在请求头中增加一个Origin字段,
  • 服务器收到请求后,根据该字段判断是否允许该请求访问,如果允许,则在
    HTTP头信息中添加Access-Control-Allow-Origin字段。

非简单请求

  • 对于非简单请求的跨源请求,浏览器会在真实请求发出前增加一次OPTION请
    求,称为预检请求(preflight request)
  • 预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到
    HTTP头信息字段中,询问服务器是否允许这样的操作。
  • 例如一个GET请求:
  • Access-Control-Request-Method表示请求使用的HTTP方法,Access- Control-Request-Headers包含请求的自定义头字段-
  • 服务器收到请求时,需要分别对Origin、Access-Control-Request-Method、
    Access-Control-Request-Headers进行验证,验证通过后,会在返回HTTP头
    信息中添加:
  • Access-Control-Allow-Methods、Access-Control-Allow-Headers:真实请
    求允许的方法、允许使用的字段
  • Access-Control-Allow-Credentials: 是否允许用户发送、处理cookie
  • Access-Control-Max-Age: 预检请求的有效期,单位为秒,有效期内不会重复
    发送预检请求。
    非简单请求
  • 当预检请求通过后,浏览器才会发送真实请求到服务器。这样就实现了跨域资
    源的请求访问。

Spring Boot中配置CORS

加一个CorsConfig文件

package org.example.mpdemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .maxAge(168000)
                .allowedHeaders("*");
//                .allowCredentials(true);
    }
}
根据 W3C 的 CORS 规范,当服务器的响应中包含 Access-Control-Allow-Credentials: true 时,Access-Control-Allow-Origin 头不能设置为通配符 *。它必须明确指定一个或多个允许的来源域名。

对单个控制器进行处理

加上一个@CrossOrigin就可以了,但是仅对此控制器有效,不是全局的。

@RestController
@CrossOrigin
public class UserController { 
}
最后修改:2025 年 11 月 13 日