SpringBoot项目实战(001)mybatis通过xml实现mapper

说明

尝试做一个springboot的框架demo,不足之处,请留言指出,不胜感谢。
篇幅比较长,可以通过目录来找到需要的部分代码。

相关参考

以下是我的开发环境,仅做参考

开发

先做一个简单的增删改查,使用mybatis框架。之前写过注解版的《Mybatis 简单应用》,这里用的是xml配置版。

数据库

CREATE TABLE `db_laowu`.`Order` (
  `OrderId` INT NOT NULL AUTO_INCREMENT,
  `Code` VARCHAR(45) NOT NULL,
  `Name` VARCHAR(45) NOT NULL,
  `CreateTime` VARCHAR(45) NOT NULL,
  `LeftAmount` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`OrderId`));

CREATE TABLE `db_laowu`.`OrderDetail` (
  `OrderDetailId` INT NOT NULL AUTO_INCREMENT,
  `OrderId` INT NOT NULL,
  `ProductId` INT NOT NULL,
  `ProductCount` INT NOT NULL,
  PRIMARY KEY (`OrderDetailId`));  

创建项目

我是用vscode创建的,通过命令行:

  1. “spring Initializr: generate a maven project” 使用springboot工具创建maven项目
  2. “java” 选择语言
  3. “com.it_laowu.springboot-study” groupId
  4. “springboot-study-demo” artifactId
  5. “2.0.6” version,这个可以在pom里面改

依赖初步选择了以下,有缺的后面再加:

  • spring web
  • lombok
  • mysql
  • mybatis

项目分层

使用vscode的话,现在可以先分一下层,建一下文件夹,大致如下:
在这里插入图片描述

配置

application.properties改为application.yml

spring:
    application:
        name: springboot-study-demo
    profiles:
        active: dev
server:
    port: 1111
    servlet:
        context-path: /springboot-study-demo

新增application-dev.yml,包含一些环境特有的信息,这里存放下数据库链接

itlaowu:
    datasource:
        type: mysql
        //由于是容器内的mysql,这里用端口33060
        jdbc-url: jdbc:mysql://localhost:33060/db_laowu?useUnicode=true&characterEncoding=UTF-8
        username: it_laowu
        password: "!Aa123456"
        driver-class-name: com.mysql.jdbc.Driver

core

core/base下,我们存放一些基类。

BaseCondition 基础查询条件,包含排序和分页,分页放到下一章

package com.it_laowu.springbootstudy.springbootstudydemo.core.base;

import lombok.Data;

/**
 * 查询条件基类 不能直接指定sortSql,而是要校验安全性,再拼接sortType sortFields
 */
@Data
public abstract class BaseCondition {
    
    
    private String sortType;
    private String sortFields;
    private String sortSql;
    private int pageSize;
    private int currPageIndex;

    public String getSortSql() {
    
    
        if (sortFields != null && !sortFields.equals("") && !sortFields.equals("null")) {
    
    
            if ("asc,desc".indexOf(sortType.toLowerCase()) == -1) {
    
    
                return "";
            }
            final Class<?> childClass = getChildClass();
            for (String field : sortFields.split(",")) {
    
    
                try {
    
    
                    // 这里可以根据字段名,找到数据库对应的列名。本例简单认为两者相等。
                    childClass.getDeclaredField(field);
                } catch (NoSuchFieldException | SecurityException e) {
    
    
                    return "";
                }
            }
            return String.format(" ORDER BY %s %s ", sortFields, sortType);
        } else {
    
    
            return "";
        }
    }

    abstract public Class<?> getChildClass();
}

IBaseDao Dao层接口

package com.it_laowu.springbootstudy.springbootstudydemo.core.base;

import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface IBaseDao<Bean,Condition> {
    
    

    //全部查询,可以加入分页
    public List<Bean> findAll(@Param("conditionQC") Condition conditionQC);
    //该方法不对外,容易出错
    Bean findOne(@Param("keyId") int keyId);
    public int insert(Bean entity);
    public int update(Bean entity);
    public int delete(@Param("keyId") int keyId);
}

IBaseService Service接口

package com.it_laowu.springbootstudy.springbootstudydemo.core.base;

import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface IBaseService<Bean,Condition> {
    
    

    //内部方法
    IBaseDao<Bean,Condition> getBaseDao();
    default List<Bean> findAll(@Param("conditionQC") Condition condition){
    
    
        return getBaseDao().findAll(condition);
    }
    //内部方法
    default Bean findOne(@Param("keyId") int keyId){
    
    
        return getBaseDao().findOne(keyId);
    }
    default int insert(Bean entity){
    
    
        return getBaseDao().insert(entity);
    }
    default int update(Bean entity){
    
    
        return getBaseDao().update(entity);
    }
    default int delete(@Param("keyId") int keyId){
    
    
        return getBaseDao().delete(keyId);
    }
}

ResultBody 用于Controller返回数据

package com.it_laowu.springbootstudy.springbootstudydemo.core.base;

import lombok.Data;

@Data
public class ResultBody {
    
    
    private String code;
    private String message;
    private String detailMessage;

    public ResultBody() {
    
    
    }

    public ResultBody(String code, String message) {
    
    
        this.code = code;
        this.message = message;
    }

    public ResultBody(String code, String message, String detailMessage) {
    
    
        this.code = code;
        this.message = message;
        this.detailMessage = detailMessage;
    }
}

bean condition mybatis dao service impl

上面是基类,接下来实现Order表的相关类。

OrderCondition 查询条件

package com.it_laowu.springbootstudy.springbootstudydemo.bean.condition;

import java.math.BigDecimal;
import java.sql.Timestamp;

import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.BaseCondition;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class OrderCondition extends BaseCondition {
    
    
    private int orderId;
    private String code;
    private String name;
    private Timestamp createTime;
    private BigDecimal leftAmount;

    @Override
    public Class<?> getChildClass() {
    
    
        return OrderBean.class;
    }
}

OrderBean 完全按照数据字段翻过来,用于新增修改、数据校验

package com.it_laowu.springbootstudy.springbootstudydemo.bean;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Timestamp;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@SuppressWarnings("serial")
public class OrderBean implements Serializable{
    
    

    @NotNull
    private int orderId;
    @NotNull
    @Size(min = 5, max = 12,message = "长度在5-12")
    private String code;
    @NotNull
    private String name;
    @NotNull
    private Timestamp createTime;
    @Min(value=0,message="必须大于0")
    private BigDecimal leftAmount;
}

OrderDao 继承IBaseDao的方法即可。若有扩展,在子接口定义

package com.it_laowu.springbootstudy.springbootstudydemo.dao;

import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseDao;

public interface OrderDao extends IBaseDao<OrderBean,OrderCondition> {
    
    
}

IOrderService 集成IBaseService即可。若有扩展,在子接口定义

package com.it_laowu.springbootstudy.springbootstudydemo.service;

import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseService;

public interface IOrderService extends IBaseService<OrderBean,OrderCondition>  {
    
    
}

OrderServiceImpl 实现IOrderService

package com.it_laowu.springbootstudy.springbootstudydemo.service.impl;

import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseDao;
import com.it_laowu.springbootstudy.springbootstudydemo.dao.OrderDao;
import com.it_laowu.springbootstudy.springbootstudydemo.service.IOrderService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements IOrderService {
    
    
    @Autowired
    public OrderDao orderDao;

    @Override
    public IBaseDao<OrderBean, OrderCondition> getBaseDao() {
    
    
        return orderDao;
    }
}

mybatis.xml 在resource中建个目录 mybatisMappers,写下mybatis.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">

<!-- 匹配哪个dao -->
<mapper namespace="com.it_laowu.springbootstudy.springbootstudydemo.dao.OrderDao">

    <!-- 定义一个返回结构 resultMap-->
    <resultMap id="orderResultMap" type="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
        <result column="orderId" property="orderId"/>
        <result column="code" property="code"/>
        <result column="name" property="name"/>
        <result column="createTime" property="createTime"/>
        <result column="leftAmount" property="leftAmount"/>
    </resultMap>

    <select id="findAll" resultMap="orderResultMap">
        select orderId,code,`name`,createTime,leftAmount
        from `Order`
        <where>
            <if test="conditionQC.orderId != 0">
                and orderId = #{conditionQC.orderId}
            </if>
            <if test="conditionQC.code != null and '' != conditionQC.code">
                and code like concat('%',#{conditionQC.code},'%')
            </if>
            <if test="conditionQC.name != null and '' != conditionQC.name">
                and name like concat('%',#{conditionQC.name},'%')
            </if>
            <if test="conditionQC.createTime != null and '' != conditionQC.createTime">
                and createTime like concat('%',#{conditionQC.createTime},'%')
            </if>
            <if test="conditionQC.leftAmount != null and '' != conditionQC.leftAmount">
                and leftAmount like concat('%',#{conditionQC.leftAmount},'%')
            </if>
        </where>
        <choose>
            <when test="conditionQC.sortSql == null">
                order by orderId
            </when>
            <otherwise>
                ${conditionQC.sortSql}
            </otherwise>
        </choose>
    </select>
    <select id="findOne" resultMap="orderResultMap">
        select orderId,code,`name`,createTime,leftAmount
        from `Order`
        where orderId = #{keyId}
    </select>
    <insert id="insert" parameterType="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
        insert into `Order`(orderId,`code`,`name`,createTime,leftAmount)
        values(#{orderId},#{code},#{name},#{createTime},#{leftAmount})
    </insert>
    <update id="update" parameterType="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
        update `Order`
        <set>
            <if test="code!=null"> `code`=#{code}, </if>
            <if test="name!=null"> `name`=#{name}, </if>
            <if test="createTime!=null"> createTime=#{createTime}, </if>
            <if test="leftAmount!=null"> leftAmount=#{leftAmount}, </if>
        </set>
        where orderId = #{orderId}
    </update>
    <delete id="delete" parameterType="int">
        delete from `Order` where orderId = #{keyId}
    </delete>
</mapper>

controller

package com.it_laowu.springbootstudy.springbootstudydemo.controller;

import java.util.List;

import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.service.IOrderService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

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

    @Autowired
    public IOrderService orderService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String hello() {
    
    
        return "hello world:";
    }

    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public List<OrderBean> orders(OrderCondition orderCondition) {
    
    
        return orderService.findAll(orderCondition);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public OrderBean order(@PathVariable(value = "id") int id) {
    
    
        return orderService.findOne(id);
    }

    //新增时数据校验
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public int add(@Validated @RequestBody OrderBean orderBean) {
    
    
        return orderService.insert(orderBean);
    }

    //修改时不校验数据,当然高级一点会指定要更新哪些字段,然后同样校验数据
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public int update(@PathVariable(value = "id") int id, @RequestBody OrderBean orderBean) {
    
    
        return orderService.update(orderBean.setOrderId(id));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public int delete(@PathVariable(value = "id") int id) {
    
    
        return orderService.delete(id);
    }
}

建立代码和xml之间的映射关系

AppConfig 主要config文件,指定了Component和MybatisMapper的扫描路径

package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(AppConfig.COMPONENTSCAN)
@MapperScan(basePackages = AppConfig.MAPPERSCAN)
public class AppConfig {
    
    
    protected static final String COMPONENTSCAN="com.it_laowu";
    protected static final String MAPPERSCAN="com.it_laowu.**.dao";
    protected static final String MAPPERPATH="classpath*:mybatisMappers/**/*.mybatis.xml";

    public AppConfig(){
    
    
        System.out.println("AppConfig start");
    }
}

DataSourceConfig,Mybatis配置信息,及数据源

package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

@Configuration
@ConditionalOnClass(DataSource.class)
@AutoConfigureAfter(AppConfig.class)
public class DataSourceConfig {
    
    

    public DataSourceConfig(){
    
    
        System.out.println("DataSourceConfig start");
    }

    //从application-dve中读取数据库配置
    @Autowired
    private DSConfigProperties dSConfigProperties;

    @Bean(name="mybatisDataSource")
    @Primary
    @ConfigurationProperties(prefix="itlaowu.datasource")
    public DataSource dataSource() throws Exception {
    
    
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "mybatisSqlSessionFactory")
    @Primary
    @DependsOn(value = "springContextUtil")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("mybatisDataSource")  DataSource dataSource) throws Exception {
    
    
        final SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        // mybatis.xml路径
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(AppConfig.MAPPERPATH));
        // 配置mybatis config
        bean.setConfiguration(createMybatisConfig());
        // 配置数据库
        bean.setDatabaseIdProvider(new DatabaseIdProvider() {
    
    
            @Override
            public String getDatabaseId(final DataSource dataSource) throws SQLException {
    
    
                return dSConfigProperties.getType();
            }
        });
        return bean.getObject();
    }

    // mybatis配置
    private org.apache.ibatis.session.Configuration createMybatisConfig() {
    
    
        final org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
        config.setCacheEnabled(true);
        config.setLazyLoadingEnabled(true);
        config.setLogPrefix("dao.");
        config.setLocalCacheScope(LocalCacheScope.SESSION);
        return config;
    }

    @Bean(name = "mybatisSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mybatisSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
    
    
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean(name = "mybatisTransactionManager")
    public DataSourceTransactionManager mybatisMasterTransactionManager(@Qualifier("mybatisDataSource") DataSource dataSource) {
    
    
        return new DataSourceTransactionManager(dataSource);
    }
}

DSConfigProperties,读取application-dev中的数据库配置

package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import lombok.Data;

@Component
@ConfigurationProperties(prefix="itlaowu.datasource")
@Data
public class DSConfigProperties {
    
    
    private String type;
    private String jdbcUrl;
    private String username;
    private String password;
    private String driverClassName;
}

猜你喜欢

转载自blog.csdn.net/weixin_36572983/article/details/104468837