Spring Boot 2.7.0 Mybatis の概要 (2)

マイバティスとは

MyBatis は、カスタム SQL、ストアド プロシージャ、および高度なマッピングをサポートする優れた永続層フレームワークです。プリミティブ型、インターフェイス、および Java POJO (Plain Old Java Object) は、単純な XML または注釈を介してデータベース内のレコードに構成およびマッピングできます。

mybatis などのフレームワークが登場する前は、ほとんどの人が jdbc 経由でデータベースに接続し、SQL ステートメントを Java コードにつなぎ合わせて実行していました。

1. JDBC ドライバーをロードします。

Class.forName("com.mysql.jdbc.Driver") ; 

2. データベース接続を作成します。

Connection con = DriverManager.getConnection(url , username , password ) ; 

3. 準備されたステートメントを実行します。

Statement stmt = con.createStatement() ;
//PreparedStatement pstmt = con.prepareStatement(sql) ;
ResultSet rs = stmt.executeQuery("SELECT * FROM ...") ;

4. データ分析のために結果セットをスキャンします。

while(rs.next()){
    
    
   String name = rs.getString("name") ;
   String pass = rs.getString(1) ; 
}

mybatis フレームワークは、接続プールを確立するようにデータ ソースを構成できること、Java ステートメントと SQL ステートメントを個別に作成できること、SQL ステートメントを XML 構成ファイルに記述できること、インターフェイスが Java で定義されていることなど、上記のプロセスをカプセル化して最適化します。セットとエンティティ オブジェクトの変換。これにより、開発者のコ​​ーディング効率が大幅に向上し、コードの可読性が向上し、データベースのパフォーマンスが節約されます。

このチュートリアルでは次のバージョンを使用します

スプリングブーツ 2.7.0

マイボット 2.1.3

ドルイド 1.2.1

mysql5.6

統合する

プロジェクトの作成

新しい Spring Boot プロジェクトを作成します。空のプロジェクトは、前のチュートリアルで作成できます。

Spring Boot の概要

pomファイルを編集する

idea で新しい Maven プロジェクトを作成した後、まず pom ファイルに次の依存関係を導入する必要があります。

主に含まれるもの: mybatis 依存関係、druid 依存関係、mysql 依存関係

 <properties>
        <java.version>1.8</java.version>
    </properties>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
        <relativePath/>
    </parent>

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

        <!-- 测试 组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- jdbc 组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- mybatis 组件 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- druid 组件 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.1</version>
        </dependency>

        <!-- mysql 组件 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.study.MainStarter</mainClass>
                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

jar パッケージが見つからないように、依存関係をリロードすることを忘れないでください。Maven を順番にクリックし、プロジェクト名=》右クリック=》Reimport
ここに画像の説明を挿入します

ディレクトリ構造

以下に示すようにパッケージのディレクトリ構造を確立します。詳細は次のとおりです。

ここに画像の説明を挿入します

テーブル作成ステートメント

mysql5.6 データベースで設計したテーブル作成ステートメントを実行します。

CREATE DATABASE /*!32312 IF NOT EXISTS*/studydb /*!40100 DEFAULT CHARACTER SET utf8 */;
USE studydb;
DROP TABLE IF EXISTS ser_company;
CREATE TABLE ser_company (
  company_id int(11) NOT NULL AUTO_INCREMENT COMMENT '公司id',
  company_name varchar(64) DEFAULT NULL COMMENT '公司名称',
  company_code varchar(4) DEFAULT NULL COMMENT '公司编号',
  company_msg text COMMENT '公司简介',
  company_crdt timestamp NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (company_id)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;

データソースとmybatisの設定

次の設定を application.properties 設定ファイルに追加します

#druid数据库连接池
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#数据库地址
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/studydb?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
#数据库账号
spring.datasource.username=root
#数据库密码
spring.datasource.password=root

#清除缓存
spring.thymeleaf.cache=false
#配置mapper映射路径
mybatis.mapper-locations=classpath:mapper/*.xml
#配置实体别名包路径
mybatis.type-aliases-package=com.study.model
#日志级别
logging.level.com.study.* = debug

上記の構成ファイル内のデータベース アドレス、アカウント、パスワード、マッパー マッピング パス、エンティティ エイリアス パス、およびログを独自のデータベースに合わせて変更する必要があることに注意してください。マッパー マッピング パスを構成すると、Spring Boot コンテナー中にこのパス内のファイルが自動的にスキャンされます。エンティティのエイリアス パッケージ パスを設定すると、xml にクラス名を記述するときにエンティティ クラスのパッケージ名を記述する必要がなくなります。ここでは、Alibaba druid データベース接続コンポーネントが使用されます。

エンティティクラス

ser_company テーブル内のエンティティに対応するエンティティ クラスを com.study.model パッケージの下に作成します。例として会社オブジェクトを考えてみましょう。このオブジェクトには、会社名、会社コード、会社情報、保管時間などのフィールドが含まれています。コードは以下のように表示されます。

package com.study.model;

import org.apache.ibatis.type.Alias;

@Alias("SerCompanyVO")
public class SerCompanyVO {
    
    

    private int companyId;
    private String companyName;
    private String companyCode;
    private String companyMsg;
    private String companyCrdt;

    public int getCompanyId() {
    
    
        return companyId;
    }

    public void setCompanyId(int companyId) {
    
    
        this.companyId = companyId;
    }

    public String getCompanyName() {
    
    
        return companyName;
    }

    public void setCompanyName(String companyName) {
    
    
        this.companyName = companyName;
    }

    public String getCompanyCode() {
    
    
        return companyCode;
    }

    public void setCompanyCode(String companyCode) {
    
    
        this.companyCode = companyCode;
    }

    public String getCompanyMsg() {
    
    
        return companyMsg;
    }

    public void setCompanyMsg(String companyMsg) {
    
    
        this.companyMsg = companyMsg;
    }

    public String getCompanyCrdt() {
    
    
        return companyCrdt;
    }

    public void setCompanyCrdt(String companyCrdt) {
    
    
        this.companyCrdt = companyCrdt;
    }
}

だお

com.study.dao パッケージの下の SerCompanyMapper クラスを編集して、関連するインターフェイスを XML にマップします。ここでは、練習用に selectSerCompanyList などのインターフェイスを選択できます。このチュートリアルにはいくつかのインターフェイスが含まれています。クエリの追加、変更、削除に加えて。このチュートリアルには、バッチ挿入、動的ステートメントの挿入と主キーの戻り、動的ステートメントの変更などのサンプル インターフェイスが含まれています。コードは以下のように表示されます。

package com.study.dao;

import com.study.model.SerCompanyVO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SerCompanyMapper {
    
    

    /**
     * 查询全部数据
     * @return
     */
    List<SerCompanyVO> selectSerCompanyList();

    /**
     * 根据id查询信息
     * @return
     */
    SerCompanyVO  selectSerCompanyById(Integer companyId);

    /**
     * 固定字段插入
     * @param serCompanyVO
     * @return
     */
    int insertSerCompanyVO(SerCompanyVO serCompanyVO);

    /**
     * 动态语句插入
     * @param serCompanyVO
     * @return
     */
    int insertSerCompanyDynamic(SerCompanyVO serCompanyVO);

    /**
     * 批量插入
     * @param list
     * @return
     */
    int insertCompanyBatch(List<SerCompanyVO> list);

    /**
     * 修改信息
     * @param serCompanyVO
     * @return
     */
    int updateCompany(SerCompanyVO serCompanyVO);

    /**
     * 动态语句修改
     * @param serCompanyVO
     * @return
     */
    int updateCompanyDynamic(SerCompanyVO serCompanyVO);

    /**
     * 根据id删除信息
     * @param companyId
     * @return
     */
    int deleteCompanyById(Integer companyId);
}

XML

マッパー ディレクトリに新しい SerCompanyMapper.xml を作成し、次のコードを記述します。

namespace は、dao 層インターフェイス クラスのパスです。

resultMap は、クエリ結果セットを SerCompanyVO オブジェクトにカプセル化します。

foreach タグはリスト パラメーターを横断できます。

useGeneratedKeys と keyProperty は、挿入後に主キーを返すことができます。

<?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="com.study.dao.SerCompanyMapper">

    <resultMap id="resultMap" type="SerCompanyVO">
        <id column="company_id" property="companyId" jdbcType="INTEGER" />
        <result column="company_name" property="companyName" jdbcType="VARCHAR" />
        <result column="company_code" property="companyCode" jdbcType="VARCHAR" />
        <result column="company_msg" property="companyMsg" jdbcType="VARCHAR" />
        <result column="company_crdt" property="companyCrdt" jdbcType="VARCHAR" />
    </resultMap>

    <!-- 新增数据 固定语句 -->
    <insert id="insertSerCompanyVO" useGeneratedKeys="true" keyProperty="companyId">
        insert into ser_company(
            company_name,
            company_code,
            company_msg,
            company_crdt
        ) values (
            #{companyName, jdbcType=VARCHAR},
            #{companyCode, jdbcType=VARCHAR},
            #{companyMsg, jdbcType=VARCHAR},
            #{companyCrdt, jdbcType=TIMESTAMP}
        )
    </insert>

    <!-- 新增数据 动态语句 -->
    <insert id="insertSerCompanyDynamic" useGeneratedKeys="true" keyProperty="companyId">
        insert into ser_company(
            <if test="null != companyName and ''!= companyName">
                company_name,
            </if>
            <if test="null != companyCode and ''!= companyCode">
                company_code,
            </if>
            <if test="null != companyMsg and ''!= companyMsg">
                company_msg,
            </if>
            <if test="null != companyCrdt and ''!= companyCrdt">
                company_crdt
            </if>
        ) values (
            <if test="null != companyName and ''!= companyName">
                #{companyName, jdbcType=VARCHAR},
            </if>
            <if test="null != companyCode and ''!= companyCode">
                #{companyCode, jdbcType=VARCHAR},
            </if>
            <if test="null != companyMsg and ''!= companyMsg">
                #{companyMsg, jdbcType=VARCHAR},
            </if>
            <if test="null != companyCrdt and ''!= companyCrdt">
                #{companyCrdt, jdbcType=TIMESTAMP}
            </if>
        )
    </insert>

    <!-- 新增数据 批量插入 -->
    <insert id="insertCompanyBatch">
        insert into ser_company(
            company_name,
            company_code,
            company_msg,
            company_crdt
        ) values
        <foreach collection="list" item="item" separator=",">
            (
                #{item.companyName, jdbcType=VARCHAR},
                #{item.companyCode, jdbcType=VARCHAR},
                #{item.companyMsg, jdbcType=VARCHAR},
                #{item.companyCrdt, jdbcType=TIMESTAMP}
            )
        </foreach>
    </insert>

    <update id="updateCompanyDynamic" >
        update ser_company set
        <if test="null != companyName and ''!= companyName">
            company_name = #{companyName, jdbcType=VARCHAR},
        </if>
        <if test="null != companyCode and ''!= companyCode">
            company_code = #{companyCode, jdbcType=VARCHAR},
        </if>
        <if test="null != companyMsg and ''!= companyMsg">
            company_msg = #{companyMsg, jdbcType=VARCHAR},
        </if>
        <if test="null != companyCrdt and ''!= companyCrdt">
            company_crdt =  #{companyCrdt, jdbcType=TIMESTAMP}
        </if>
        where company_id = #{companyId, jdbcType=INTEGER}
    </update>

    <update id="updateCompany">
        update ser_company set
        company_name = #{companyName, jdbcType=VARCHAR},
        company_code = #{companyCode, jdbcType=VARCHAR},
        company_msg = #{companyMsg, jdbcType=VARCHAR},
        company_crdt = #{companyCrdt, jdbcType=TIMESTAMP}
        where company_id = #{companyId, jdbcType=INTEGER}
    </update>

    <!-- 删除数据 -->
    <delete id="deleteCompanyById">
        delete from ser_company where company_id = #{companyId, jdbcType=INTEGER}
    </delete>

    <!-- 查询数据 -->
    <select id="selectSerCompanyList" resultMap="resultMap">
        select company_name, company_code, company_msg, company_crdt from ser_company
    </select>

    <!-- 详情查询 -->
    <select id="selectSerCompanyById" resultMap="resultMap" parameterType="java.lang.Integer">
        select company_id,company_name, company_code, company_msg, company_crdt from ser_company where company_id=#{companyId, jdbcType=INTEGER}
    </select>
</mapper>

サービスクラスと実装クラス

com.study.service パッケージの下に新しい SerCompanyService インターフェイスを作成します。コードは次のとおりです。

package com.study.service;

import com.study.model.SerCompanyVO;

import java.util.List;

public interface SerCompanyService {
    
    

    List<SerCompanyVO> querySerCompanyList();

    int addCompany(SerCompanyVO serCompanyVO);

    int addCompanyDynamic(SerCompanyVO serCompanyVO);

    int addCompanyBatch(List<SerCompanyVO> list);

    SerCompanyVO querySerCompanyById(Integer companyId);

    int updateCompany(SerCompanyVO serCompanyVO);

    int updateCompanyDynamic(SerCompanyVO serCompanyVO);

    int deleteCompanyById(Integer companyId);
}

新しい SerCompanyServiceImpl 実装クラスを com.study.service.impl パッケージの下に作成します。コードは次のとおりです。

ここでは、先ほど作成した SerCompanyMapper を使用します。このクラスを使用して、mybatis XML 内のステートメントを呼び出します。

package com.study.service.impl;

import com.study.dao.SerCompanyMapper;
import com.study.model.SerCompanyVO;
import com.study.service.SerCompanyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SerCompanyServiceImpl implements SerCompanyService {
    
    

    private Logger log = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    private SerCompanyMapper serCompanyMapper;

    @Override
    public List<SerCompanyVO> querySerCompanyList() {
    
    
        return serCompanyMapper.selectSerCompanyList();
    }

    @Override
    public int addCompany(SerCompanyVO serCompanyVO) {
    
    
        return serCompanyMapper.insertSerCompanyVO(serCompanyVO);
    }

    @Override
    public int addCompanyDynamic(SerCompanyVO serCompanyVO) {
    
    
        return serCompanyMapper.insertSerCompanyDynamic(serCompanyVO);
    }

    @Override
    public int addCompanyBatch(List<SerCompanyVO> list) {
    
    
        return serCompanyMapper.insertCompanyBatch(list);
    }

    @Override
    public SerCompanyVO querySerCompanyById(Integer companyId) {
    
    
        return serCompanyMapper.selectSerCompanyById(companyId);
    }

    @Override
    public int updateCompany(SerCompanyVO serCompanyVO) {
    
    
        return serCompanyMapper.updateCompany(serCompanyVO);
    }

    @Override
    public int updateCompanyDynamic(SerCompanyVO serCompanyVO) {
    
    
        return serCompanyMapper.updateCompanyDynamic(serCompanyVO);
    }

    @Override
    public int deleteCompanyById(Integer companyId) {
    
    
        return serCompanyMapper.deleteCompanyById(companyId);
    }
}

コントローラ

com.study.controller に次のクラスを作成します。

package com.study.controller;

import com.study.model.SerCompanyVO;
import com.study.service.SerCompanyService;
import com.study.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Controller
public class SerCompanyController {
    
    

    private Logger log = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    private SerCompanyService serCompanyService;

    /**
     * 查询公司信息列表
     * http://localhost:8080/querySerCompanyList
     * @return
     */
    @RequestMapping(method= RequestMethod.GET, value = "querySerCompanyList")
    @ResponseBody
    public List<SerCompanyVO> querySerCompanyList(){
    
    
        if(log.isDebugEnabled()){
    
    
            log.debug("do querySerCompanyList begin.");
        }
        return serCompanyService.querySerCompanyList();
    }

    /**
     * 查询公司信息根据id
     * http://localhost:8080/querySerCompanyById?companyId=1
     * @return
     */
    @RequestMapping(method= RequestMethod.GET, value = "querySerCompanyById")
    @ResponseBody
    public SerCompanyVO querySerCompanyById(Integer companyId){
    
    
        return serCompanyService.querySerCompanyById(companyId);
    }

    /**
     * 新增公司固定字段
     * @param serCompanyVO
     * http://localhost:8080/addCompany?companyName=百度&companyCode=321&companyMsg=百度是一家上市公司
     * @return
     */
    @RequestMapping(method= RequestMethod.GET, value = "addCompany")
    @ResponseBody
    public Map<String, Object> addCompany(SerCompanyVO serCompanyVO){
    
    
        if(log.isDebugEnabled()){
    
    
            log.debug("companyName:{}", serCompanyVO.getCompanyName());
        }
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        serCompanyVO.setCompanyCrdt(timestamp.toString());
        int num = serCompanyService.addCompany(serCompanyVO);
        Map<String ,Object> map =  ResultUtil.getRsMap(num);
        map.put("serCompanyVO", serCompanyVO);
        return map;
    }

    /**
     * 新增公司动态字段
     * http://localhost:8080/addCompanyDynamic?companyName=字节跳动&companyCode=&companyMsg=
     * @param serCompanyVO
     * @return
     */
    @RequestMapping(method= RequestMethod.GET, value = "addCompanyDynamic")
    @ResponseBody
    public Map<String, Object> addCompanyDynamic(SerCompanyVO serCompanyVO){
    
    
        if (log.isDebugEnabled()){
    
    
            log.debug("companyName:{}", serCompanyVO.getCompanyName());
        }
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        serCompanyVO.setCompanyCrdt(timestamp.toString());
        int num = serCompanyService.addCompanyDynamic(serCompanyVO);
        Map<String ,Object> map =  ResultUtil.getRsMap(num);
        map.put("serCompanyVO", serCompanyVO);
        return map;
    }

    /**
     * 批量新增公司
     * http://localhost:8080/addCompanyBatch
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "addCompanyBatch")
    @ResponseBody
    public Map<String, Object> addCompanyBatch(){
    
    
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        String timeStr = timestamp.toString();
        SerCompanyVO serCompanyVO = new SerCompanyVO();
        serCompanyVO.setCompanyName("导入1");
        serCompanyVO.setCompanyCode("3301");
        serCompanyVO.setCompanyCrdt(timeStr);
        SerCompanyVO serCompanyVO1 = new SerCompanyVO();
        serCompanyVO1.setCompanyName("导入2");
        serCompanyVO1.setCompanyCode("3302");
        serCompanyVO1.setCompanyCrdt(timeStr);
        List<SerCompanyVO> list = new ArrayList<>();
        list.add(serCompanyVO);
        list.add(serCompanyVO1);
        int num = serCompanyService.addCompanyBatch(list);
        return ResultUtil.getRsMap(num);
    }

    /**
     * 修改公司信息 固定语句
     * http://localhost:8080/updateCompany?companyId=13&companyName=百度2&companyCode=333&companyMsg=百度2是一家上市公司
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "updateCompany")
    @ResponseBody
    public Map<String, Object> updateCompany(SerCompanyVO serCompanyVO){
    
    
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        String timeStr = timestamp.toString();
        serCompanyVO.setCompanyCrdt(timeStr);
        int num = serCompanyService.updateCompany(serCompanyVO);
        return  ResultUtil.getRsMap(num);
    }

    /**
     * 修改公司信息 动态语句
     * http://localhost:8080/updateCompanyDynamic?companyId=13&companyName=百度3&companyCode=333
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "updateCompanyDynamic")
    @ResponseBody
    public Map<String, Object> updateCompanyDynamic(SerCompanyVO serCompanyVO){
    
    
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        String timeStr = timestamp.toString();
        serCompanyVO.setCompanyCrdt(timeStr);
        int num = serCompanyService.updateCompanyDynamic(serCompanyVO);
        return  ResultUtil.getRsMap(num);
    }

    /**
     * 删除公司信息
     * http://localhost:8080/deleteCompanyById?companyId=15
     * @param companyId
     * @return
     */
    @RequestMapping(method = RequestMethod.GET, value = "deleteCompanyById")
    @ResponseBody
    public Map<String, Object> deleteCompanyById(Integer companyId){
    
    
        int num = serCompanyService.deleteCompanyById(companyId);
        return  ResultUtil.getRsMap(num);
    }
}

スタートアップクラス

Spring Boot 起動用に com.study に MainStarter クラスを記述します。コードは次のとおりです。

package com.study;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MainStarter {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(MainStarter.class, args);
    }

}

テスト

右クリックして MainStarter クラスを実行します。次のようにコンソール出力を確認し、プロジェクトが正常に開始されることを確認します。

ここに画像の説明を挿入します

ブラウザを開き、インターフェイス テスト用に次のアドレスを入力し、データをクエリするインターフェイスを選択します。

http://localhost:8080/querySerCompanyList

結果は次のとおりです

ここに画像の説明を挿入します

他のインターフェイス アドレスはコントローラー クラスで見つかり、順番にテストできます。

さて、mybatis と Spring Boot の統合は基本的に完了しました。

最後に書きます

オープンソースは美徳です。できるだけ早くオープンソース コミュニティに参加し、美しいエコシステムを一緒に構築してください。

おすすめ

転載: blog.csdn.net/qq_36378416/article/details/125444521