(入门) SpringBoot + Mybatis 从0到1

39 阅读5分钟

项目结构

Mybatis-demo
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com.example.demo
│   │   │       ├── common          // 公共模块:存放统一返回结果 Result 类
│   │   │       ├── config          // 配置类:MyBatis 映射配置、全局异常处理
│   │   │       ├── controller      // 控制层:接受请求,调用 Service
│   │   │       ├── entity          // 实体层:与数据库表一一对应的 Java 对象
│   │   │       ├── mapper          // 持久层:MyBatis 接口文件
│   │   │       └── service         // 业务层:接口与实现类 (impl)
│   │   │           └── impl
│   │   └── resources
│   │       ├── mapper              // 存放 MyBatis 的 XML 映射文件
│   │       ├── application.yml     // 核心配置文件
│   │       └── static/templates    // 静态资源/模板(前后端分离项目通常为空)
│   └── test                        // 单元测试
├── pom.xml                         // Maven 依赖管理
└── .gitignore                      // 忽略提交的文件

1 数据库准备 SQL

-- 创建用户表
CREATE TABLE user (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    age INT
);

-- 创建订单表
CREATE TABLE `order` (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    order_no VARCHAR(50) NOT NULL,
    amount DECIMAL(10,2),
    user_id BIGINT,
    FOREIGN KEY (user_id) REFERENCES user(id)
);

-- 插入示例数据
INSERT INTO user (username, email, age) VALUES 
('张三', 'zhangsan@example.com', 25),
('李四', 'lisi@example.com', 30),
('王五', 'wangwu@example.com', 28);

INSERT INTO `order` (order_no, amount, user_id) VALUES 
('ORD001', 99.99, 1),
('ORD002', 199.99, 2),
('ORD003', 299.99, 1);

2 项目构建

创建选择maven ,JDK 17

ef4a0cb3-aa71-4c00-94b5-82e7f0cccffb.png

4abda61b-97eb-4a04-8a8c-0e84d9eae2c6.png

3 项目依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version> <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>springboot-mybatis-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mybatis-demo</name>
    <description>Spring Boot 3 + MyBatis Quick Start</description>

    <properties>
        <java.version>17</java.version> <mybatis.version>3.0.3</mybatis.version> </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>

        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>

</project>

4 yml文件关键配置

application.yml

spring:
  application:
    name: Mybatis-demo
  datasource:
    url: jdbc:mysql://localhost:3306/mybatisdemo?useSSL=false&serverTimezone=UTC
    username: root
    password: 
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: org.example.mybatisdemo.entity
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

5 创建实体类

User.java

package org.example.mybatisdemo.entity;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String orderNo;
    private Double amount;
    private Long userId;
    // 关键:为了显示多表联查的结果,添加这个字段
    private String username;
}

Order.java

package org.example.mybatisdemo.entity;

import lombok.Data;

@Data
public class Order {
    private Long id;
    private String orderNo;
    private Double amount;
    private Long userId;
    // 关键:为了显示多表联查的结果,添加这个字段
    private String username;
}

6 Mapper 接口与 XML (mapper 包)

实现mapper层 数据访问接口

UserMapper .java

package org.example.mybatisdemo.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.example.mybatisdemo.entity.User;
import java.util.List;

@Mapper
public interface UserMapper {

    // 查询所有用户
    List<User> findAll();

    // 根据ID查询用户
    User findById(Long id);

    // 添加用户
    int insert(User user);

    // 更新用户
    int update(User user);

    // 删除用户
    int delete(Long id);
}

OrderMapper.java

package org.example.mybatisdemo.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.example.mybatisdemo.entity.Order;
import java.util.List;

@Mapper
public interface OrderMapper {

    // 查询所有订单
    List<Order> findAll();

    // 根据ID查询订单
    Order findById(Long id);

    // 添加订单
    int insert(Order order);

    // 更新订单
    int update(Order order);

    // 删除订单
    int delete(Long id);
}

在src/main/resources/mapper/UserMapper.xml和 OrderMapper.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="org.example.mybatisdemo.mapper.UserMapper">

    <resultMap id="BaseResultMap" type="org.example.mybatisdemo.entity.User">
        <id column="id" property="id" />
        <result column="username" property="username" />
        <result column="email" property="email" />
        <result column="age" property="age" />
    </resultMap>

    <sql id="Base_Column_List">
        id, username, email, age
    </sql>

    <select id="findAll" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List" />
        FROM user
    </select>

    <select id="findById" parameterType="java.lang.Long" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List" />
        FROM user
        WHERE id = #{id}
    </select>

    <insert id="insert" parameterType="org.example.mybatisdemo.entity.User">
        INSERT INTO user (username, email, age)
        VALUES (#{username}, #{email}, #{age})
    </insert>

    <update id="update" parameterType="org.example.mybatisdemo.entity.User">
        UPDATE user
        SET
            <if test="username != null">username = #{username},</if>
            <if test="email != null">email = #{email},</if>
            <if test="age != null">age = #{age}</if>
        WHERE id = #{id}
    </update>

    <delete id="delete" parameterType="java.lang.Long">
        DELETE FROM user WHERE id = #{id}
    </delete>

</mapper>

OrderMapper.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="org.example.mybatisdemo.mapper.OrderMapper">

    <resultMap id="BaseResultMap" type="org.example.mybatisdemo.entity.Order">
        <id column="id" property="id" />
        <result column="order_no" property="orderNo" />
        <result column="amount" property="amount" />
        <result column="user_id" property="userId" />
        <result column="username" property="username" />
    </resultMap>

    <sql id="Base_Column_List">
        id, order_no, amount, user_id
    </sql>

    <select id="findAll" resultMap="BaseResultMap">
        SELECT o.id, o.order_no, o.amount, o.user_id, u.username
        FROM `order` o
        LEFT JOIN user u ON o.user_id = u.id
    </select>

    <select id="findById" parameterType="java.lang.Long" resultMap="BaseResultMap">
        SELECT o.id, o.order_no, o.amount, o.user_id, u.username
        FROM `order` o
        LEFT JOIN user u ON o.user_id = u.id
        WHERE o.id = #{id}
    </select>

    <insert id="insert" parameterType="org.example.mybatisdemo.entity.Order">
        INSERT INTO `order` (order_no, amount, user_id)
        VALUES (#{orderNo}, #{amount}, #{userId})
    </insert>

    <update id="update" parameterType="org.example.mybatisdemo.entity.Order">
        UPDATE `order`
        SET
            <if test="orderNo != null">order_no = #{orderNo},</if>
            <if test="amount != null">amount = #{amount},</if>
            <if test="userId != null">user_id = #{userId}</if>
        WHERE id = #{id}
    </update>

    <delete id="delete" parameterType="java.lang.Long">
        DELETE FROM `order` WHERE id = #{id}
    </delete>

</mapper>

7 Service层

UserService.java

package org.example.mybatisdemo.service;

import org.example.mybatisdemo.entity.User;
import java.util.List;

/*
* 接口不添加@Service注解,只定义方法契约
* */

public interface UserService {

    List<User> findAll();

    User findById(Long id);

    int insert(User user);

    int update(User user);

    int delete(Long id);
}

OrderService.java

package org.example.mybatisdemo.service;

import org.example.mybatisdemo.entity.Order;
import java.util.List;


public interface OrderService {

    List<Order> findAll();

    Order findById(Long id);

    int insert(Order order);

    int update(Order order);

    int delete(Long id);
}

创建service.impl包

  1. 接口-实现分离的模式。让我总结一下Service层接口-实现分离的好处:
  2. 符合面向接口编程原则:Controller依赖于Service接口而不是具体实现,符合依赖倒置原则。
  3. 便于单元测试:可以通过Mock接口来测试Controller层,而不需要依赖具体的实现。
  4. 便于扩展:如果需要提供不同的实现,只需要创建新的实现类即可。
  5. 便于AOP代理:Spring的事务管理等AOP功能通常需要基于接口进行代理。
  6. 解耦合:接口定义契约,实现类提供具体实现,降低了系统各部分之间的耦合度

UserServiceImpl.java

package org.example.mybatisdemo.service.impl;

import org.example.mybatisdemo.entity.User;
import org.example.mybatisdemo.mapper.UserMapper;
import org.example.mybatisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<User> findAll() {
        return userMapper.findAll();
    }

    @Override
    public User findById(Long id) {
        return userMapper.findById(id);
    }

    @Override
    public int insert(User user) {
        return userMapper.insert(user);
    }

    @Override
    public int update(User user) {
        return userMapper.update(user);
    }

    @Override
    public int delete(Long id) {
        return userMapper.delete(id);
    }
}

OrderServiceImpl.java

package org.example.mybatisdemo.service.impl;

import org.example.mybatisdemo.entity.Order;
import org.example.mybatisdemo.mapper.OrderMapper;
import org.example.mybatisdemo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Override
    public List<Order> findAll() {
        return orderMapper.findAll();
    }

    @Override
    public Order findById(Long id) {
        return orderMapper.findById(id);
    }

    @Override
    public int insert(Order order) {
        return orderMapper.insert(order);
    }

    @Override
    public int update(Order order) {
        return orderMapper.update(order);
    }

    @Override
    public int delete(Long id) {
        return orderMapper.delete(id);
    }
}

8 Controller层

控制层 遵循 RESTful API 设计规范:

@PathVariable 用于获取 URL 路径上的参数(如 /user/1

@RequestBody 用于接收 JSON 格式的请求体(常用于新增、修改)

AjaxResult.java: 用于统一返回格式

package org.example.mybatisdemo.common;

import java.util.HashMap;

/**
 * AjaxResult
 * 用于统一返回格式 / Unified response format
 */
public class AjaxResult extends HashMap<String, Object> {

    public AjaxResult() {}

    // 成功(无数据)/ success without data
    public static AjaxResult success() {
        AjaxResult r = new AjaxResult();
        r.put("code", 200);
        r.put("msg", "success");
        return r;
    }

    // 成功(带数据)/ success with data
    public static AjaxResult success(Object data) {
        AjaxResult r = new AjaxResult();
        r.put("code", 200);
        r.put("msg", "success");
        r.put("data", data);
        return r;
    }

    // 错误 / error
    public static AjaxResult error(String msg) {
        AjaxResult r = new AjaxResult();
        r.put("code", 500);
        r.put("msg", msg);
        return r;
    }
}

UserController.java

package org.example.mybatisdemo.controller;

import org.example.mybatisdemo.entity.User;
import org.example.mybatisdemo.service.UserService;
import org.example.mybatisdemo.common.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/list")
    public AjaxResult list() {
        List<User> users = userService.findAll();
        return AjaxResult.success(users);
    }

    @GetMapping("/{id}")
    public AjaxResult getById(@PathVariable Long id) {
        User user = userService.findById(id);
        return AjaxResult.success(user);
    }

    @PostMapping
    public AjaxResult add(@RequestBody User user) {
        int result = userService.insert(user);
        if (result > 0) {
            return AjaxResult.success("添加成功");
        } else {
            return AjaxResult.error("添加失败");
        }
    }

    @PutMapping
    public AjaxResult edit(@RequestBody User user) {
        int result = userService.update(user);
        if (result > 0) {
            return AjaxResult.success("更新成功");
        } else {
            return AjaxResult.error("更新失败");
        }
    }

    @DeleteMapping("/{id}")
    public AjaxResult delete(@PathVariable Long id) {
        int result = userService.delete(id);
        if (result > 0) {
            return AjaxResult.success("删除成功");
        } else {
            return AjaxResult.error("删除失败");
        }
    }
}

OrderController.java

package org.example.mybatisdemo.controller;

import org.example.mybatisdemo.entity.Order;
import org.example.mybatisdemo.service.OrderService;
import org.example.mybatisdemo.common.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/list")
    public AjaxResult list() {
        List<Order> orders = orderService.findAll();
        return AjaxResult.success(orders);
    }

    @GetMapping("/{id}")
    public AjaxResult getById(@PathVariable Long id) {
        Order order = orderService.findById(id);
        return AjaxResult.success(order);
    }

    @PostMapping
    public AjaxResult add(@RequestBody Order order) {
        int result = orderService.insert(order);
        if (result > 0) {
            return AjaxResult.success("添加成功");
        } else {
            return AjaxResult.error("添加失败");
        }
    }

    @PutMapping
    public AjaxResult edit(@RequestBody Order order) {
        int result = orderService.update(order);
        if (result > 0) {
            return AjaxResult.success("更新成功");
        } else {
            return AjaxResult.error("更新失败");
        }
    }

    @DeleteMapping("/{id}")
    public AjaxResult delete(@PathVariable Long id) {
        int result = orderService.delete(id);
        if (result > 0) {
            return AjaxResult.success("删除成功");
        } else {
            return AjaxResult.error("删除失败");
        }
    }
}

10 启动项目

10a58ca8-b241-4ca4-a55a-9ae2e745b63b.png 端口号8080 接下来可以去postman测试接口了