ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MyBatisPlus2

2021-01-15 12:00:47  阅读:139  来源: 互联网

标签:param entity MyBatisPlus2 wrapper import new public


紧接上集
我们配置使用MyBatisPlus完成并且完成了查询,我们这次主要是完成剩下的操作

首先我们先看看还有哪些操作我们没有做呢,

我们进入源码看到还有

/**
 * Copyright (c) 2011-2020, hubin (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.mapper;

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

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.RowBounds;

/**
 * <p>
 * Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
 * </p>
 * <p>
 * 这个 Mapper 支持 id 泛型
 * </p>
 *
 * @author hubin
 * @Date 2016-01-23
 */
public interface BaseMapper<T> {

    /**
     * <p>
     * 插入一条记录
     * </p>
     *
     * @param entity 实体对象
     * @return int
     */
    Integer insert(T entity);

    /**
     * <p>
     * 插入一条记录
     * </p>
     *
     * @param entity 实体对象
     * @return int
     */
    Integer insertAllColumn(T entity);

    /**
     * <p>
     * 根据 ID 删除
     * </p>
     *
     * @param id 主键ID
     * @return int
     */
    Integer deleteById(Serializable id);

    /**
     * <p>
     * 根据 columnMap 条件,删除记录
     * </p>
     *
     * @param columnMap 表字段 map 对象
     * @return int
     */
    Integer deleteByMap(@Param("cm") Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,删除记录
     * </p>
     *
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return int
     */
    Integer delete(@Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 删除(根据ID 批量删除)
     * </p>
     *
     * @param idList 主键ID列表
     * @return int
     */
    Integer deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    /**
     * <p>
     * 根据 ID 修改
     * </p>
     *
     * @param entity 实体对象
     * @return int
     */
    Integer updateById(@Param("et") T entity);

    /**
     * <p>
     * 根据 ID 修改
     * </p>
     *
     * @param entity 实体对象
     * @return int
     */
    Integer updateAllColumnById(@Param("et") T entity);

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param entity  实体对象
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return
     */
    Integer update(@Param("et") T entity, @Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 whereEntity 条件,更新记录
     * </p>
     *
     * @param setStr  set字符串
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return
     */
    Integer updateForSet(@Param("setStr") String setStr, @Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 ID 查询
     * </p>
     *
     * @param id 主键ID
     * @return T
     */
    T selectById(Serializable id);

    /**
     * <p>
     * 查询(根据ID 批量查询)
     * </p>
     *
     * @param idList 主键ID列表
     * @return List<T>
     */
    List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);

    /**
     * <p>
     * 查询(根据 columnMap 条件)
     * </p>
     *
     * @param columnMap 表字段 map 对象
     * @return List<T>
     */
    List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);

    /**
     * <p>
     * 根据 entity 条件,查询一条记录
     * </p>
     *
     * @param entity 实体对象
     * @return T
     */
    T selectOne(@Param("ew") T entity);

    /**
     * <p>
     * 根据 Wrapper 条件,查询总记录数
     * </p>
     *
     * @param wrapper 实体对象
     * @return int
     */
    Integer selectCount(@Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录
     * </p>
     *
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<T> selectList(@Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * </p>
     *
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录
     * 注意: 只返回第一个字段的值
     * </p>
     *
     * @param wrapper 实体对象封装操作类(可以为 null)
     * @return List<Object>
     */
    List<Object> selectObjs(@Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 entity 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param rowBounds 分页查询条件(可以为 RowBounds.DEFAULT)
     * @param wrapper   实体对象封装操作类(可以为 null)
     * @return List<T>
     */
    List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

    /**
     * <p>
     * 根据 Wrapper 条件,查询全部记录(并翻页)
     * </p>
     *
     * @param rowBounds 分页查询条件(可以为 RowBounds.DEFAULT)
     * @param wrapper   实体对象封装操作类
     * @return List<Map<String, Object>>
     */
    List<Map<String, Object>> selectMapsPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);

}

以上方法都是我们MyBatisPlus的增强我们一个一个实现

//查询 并通过id查询
@Test
	public void test02() {
		 System.out.println(empDao.selectById(1));
	}
	
//添加
@Test
	public void insert() {
		Employee entity = new Employee();
		entity.setEmail("2073362105@qq.com");
		entity.setAge(30);
		entity.setGender(1);
		entity.setLastName("ddd");
		empDao.insert(entity);
	}
	
//添加所有列(所有的列都会添加数据,如果没有数据则为null)
@Test
	public void insertAllCoulum() {
		Employee entity = new Employee();
		entity.setEmail("2073362105@qq.com");
		entity.setAge(18);
		entity.setGender(1);
		entity.setLastName("张三");
		empDao.insert(entity);
	}
	
//通过id删除
@Test
	public void deleteById() {
		int id = 24;
		int a = empDao.deleteById(id);//通过id 删除
	}
	
//删除数据根据字段(条件设置为字段)
@Test
	public void deleteByMap() {
		Map<String,Object> columnMap = new HashMap<String,Object>();
		columnMap.put("age",18);//填入字段名
		empDao.deleteByMap(columnMap);
	}

//删除数据根据条件(wrapper代表条件)
@Test
	public void deletewrapper() {
	//new 一个 wrapper
		EntityWrapper<Employee> wrapper = new EntityWrapper<>(); 
		//le代表<=  使用or连接下一个条件 like模糊查询
		wrapper.le("age",19).or().like("last_name", "b");
		empDao.delete(wrapper);
	}

//批量删除
@Test
	public void deleteBat() {
	//删除id为20 21 的 数据
		empDao.deleteBatchIds(Arrays.asList(new Integer[] {20,21}));
	}

//修改
@Test
	public void updateByid() {
		Employee entity = new Employee();
		entity.setAge(88);
		entity.setLastName("saad");
		entity.setId(18);
		entity.setVersion(1);
		empDao.updateById(entity);
	}

//修改全部列(如果没有值则为null)
@Test
	public void updateAllColumnByid() {
		Employee entity = new Employee();
		entity.setEmail("200000@qq.com");
		entity.setGender(1);
		entity.setAge(88);
		entity.setLastName("eee");
		entity.setId(18);
		empDao.updateAllColumnById(entity);
	}

//通过条件修改
@Test 
	public void update() {
		Employee entity = new Employee();
		entity.setEmail("20asdasd00@qq.com");
		entity.setGender(1);
		entity.setAge(44);
		entity.setLastName("jjj");
		entity.setId(22);
		//new EntityWrapper<Employee>().between("age", 30 , 50)这个相当于条件
		empDao.update(entity,new EntityWrapper<Employee>().between("age", 30 , 50));
	}

//修改根据条件
@Test
	public void updateForSet() {
		empDao.updateForSet("age = 88",new EntityWrapper<Employee().gt("last_name","eee"));
	}
	
//根据id批量查询
@Test
	public void selectBatchIds() {
		empDao.selectBatchIds(Arrays.asList(new Integer[]{19,22})).forEach(System.out::println);
	}

//查询根据map条件
	@Test
	public void selectByMap() {
		Map<String,Object> columnMap = new HashMap<String,Object>();
		columnMap.put("id", 18);
		columnMap.put("id", 19);
		empDao.selectByMap(columnMap);
	}

//根据entity查询一条数据
	@Test
	public void selectOne() {
		Employee entity = new Employee();
		entity.setLastName("jjj");
		System.out.println(empDao.selectOne(entity));
		
	}
	
	//查询总条数
	@Test
	public void selectCount() {
		System.out.println(empDao.selectCount(new EntityWrapper<Employee>().gt("age",10)));
	}


//根据entity查询全部数据
	@Test
	public void selectList() {
		System.out.println(empDao.selectList(new EntityWrapper<Employee>().eq("last_name","jjj")));
	}

//根据wwrapper条件查询全部记录
	@Test
	public void selectMaps() {
		empDao.selectMaps(new EntityWrapper<Employee>().gt("age",10)).forEach(System.out::println);
	}

	@Test
	public void selectObjs() {
		empDao.selectObjs(null).forEach(System.out::println);
	}
	@Test//分页查询
	public void selectPage() {
		Page<Employee> aa = new Page<>(1,2);
		empDao.selectPage(aa, null).forEach(System.out::println);
		List<Employee> esEmps = empDao.selectPage(aa, null);
		aa.setRecords(esEmps);
		aa.getRecords().forEach(System.out::println);;
		System.out.println("总页数:"+aa.getPages());
		System.out.println("总条数:"+aa.getTotal());
		System.out.println("当前页:"+aa.getCurrent());
		System.out.println("是否有上 一页:"+aa.hasPrevious());
		System.out.println("是否有下一页:"+aa.hasNext());
		
		
	}
	@Test
	public void selectMapsPage() {
		Page<Employee> aa = new Page<>(1,2);
		empDao.selectMapsPage(aa, null).forEach(System.out::println);
	}

通用 CRUD 小结
1) 以上是基本的 CRUD 操作,如您所见,我们仅仅需要继承一个 BaseMapper 即可实现 大部分单表 CRUD 操作。BaseMapper 提供了多达 17 个方法给大家使用, 可以极其方便 的实现单一、批量、分页等操作。极大的减少开发负担,难道这就是 MP 的强大之处了 吗?
2) 提出需求: 现有一个需求,我们需要分页查询 tbl_employee 表中,年龄在 18~50 之间性别为男且 姓名为 xx 的所有用户,这时候我们该如何实现上述需求呢? MyBatis : 需要在 SQL 映射文件中编写带条件查询的 SQL,并基于 PageHelper 插件完成 分页. 实现以上一个简单的需求,往往需要我们做很多重复单调的工作。普通的 Mapper 能 够解决这类痛点吗? MP: 依旧不用编写SQL 语句, MP 提供了功能强大的条件构造器 EntityWrapper

以上我们了解了MyBatisPlus的crud 接下来就是代码生成器

要是用代码生成器首先要导入依赖

  1. 模板引擎 MP 的代码生成器默认使用的是 Apache 的 Velocity 模板,当然也可以更换为别的模板 技术,例如 freemarker。此处不做过多的介绍。 需要加入 Apache Velocity 的依赖
<dependency>
	 <groupId>org.apache.velocity</groupId>
	 <artifactId>velocity-engine-core</artifactId>
	 <version>2.0</version> 
</dependency>
  1. 加入slf4j ,查看日志输出信息
<dependency> 
	<groupId>org.slf4j</groupId> 
	<artifactId>slf4j-api</artifactId> 
	<version>1.7.7</version> 
</dependency> 
<dependency> 
	<groupId>org.slf4j</groupId>
 	<artifactId>slf4j-log4j12</artifactId> 
	 <version>1.7.7</version>
</dependency>

新建
测试类添加
如下代码

package mybatisplus;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;


public class MapperTest {
	@Test
	public void testGenerator() {
		//1全局配置 
		GlobalConfig config = new GlobalConfig();
		config.setActiveRecord(false)//是否支持AR模式
		.setAuthor("qinqinqin")//作者
		.setOutputDir("mybatisplus01\\src\\main\\java")//生成路径
		.setFileOverride(true)//文件覆盖
		.setIdType(IdType.AUTO)//主键策略
		.setServiceName("%sService")//设置service接口的名字的首字线是否为I
		.setBaseResultMap(true)
		.setBaseColumnList(true);//生成sql片段
		//2.数据源配置 
		DataSourceConfig dsConfig = new DataSourceConfig();
		dsConfig.setDbType(DbType.MYSQL)//设置数据库类型
		.setDriverName("com.mysql.jdbc.Driver")
		.setUrl("jdbc:mysql://localhost:3306/mp")
		.setUsername("root")
		.setPassword("root");
		
		//3.策略配置
		StrategyConfig stConfig = new StrategyConfig();
		stConfig.setCapitalMode(true)//全局大定命名
		.setDbColumnUnderline(true)//提定数据表名   字段名是否使用了下划线
		.setNaming(NamingStrategy.underline_to_camel)//数据库表映射到实体的命名策略
		.setTablePrefix("tbl_")
		.setInclude("tbl_employee");//生成的表
		//4.包名策略配置 
		PackageConfig pkConfig = new PackageConfig();
		pkConfig.setParent("come.bdqne")
		.setMapper("mapper")
		.setService("service")
		.setController("controller")
		.setEntity("entity")
		.setXml("mapper");
		//5.整合配置 
		AutoGenerator ag = new AutoGenerator();
		ag.setGlobalConfig(config);
		ag.setDataSource(dsConfig);
		ag.setStrategy(stConfig);
		ag.setPackageInfo(pkConfig);
		//6.执行
		ag.execute();
	}
}

运行测试类即可生成
在这里插入图片描述
一些基本格式和相应的代码

插件

Mybatis 插件机制简介
1.插件机制: Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求,完成相关数据的动态改变。 Executor StatementHandler ParameterHandler ResultSetHandler
2. 插件原理 四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插 件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四 大对象相关方法的执行,因为要执行四大对象的方法需要经过代理.

分页插件
1.com.baomidou.mybatisplus.plugins.PaginationInterceptor
执行分析插件
com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
2. SQL 执行分析拦截器,只支持MySQL5.6.3 以上版本
3.该插件的作用是分析 DELETE UPDATE 语句,防止小白 或者恶意进行 DELETE UPDATE 全表操作
4.只建议在开发环境中使用,不建议在生产环境使用
5.在插件的底层 通过SQL 语句分析命令:Explain 分析当前的 SQL 语句, 根据结果集中的Extra 列来断定当前是否全表操作。

性能分析插件

  1. com.baomidou.mybatisplus.plugins.PerformanceInterceptor
  2. 性能分析拦截器,用于输出每条 SQL 语句及其执行时间
    3.SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题

乐观锁插件
1.com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor
2.如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新
3. 乐观锁的实现原理: 取出记录时,获取当前 version 2 更新时,带上这个 version 2 执行更新时, set version = yourVersion+1 where version = yourVersion 如果 version 不对,就更新失败
4. @Version 用于注解实体字段,必须要有

自定义全局操作
根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自 定义 Mybatisplus 自动注入的方法。 之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境 时就注入。
AutoSqlInjector
1.在 Mapper 接口中定义相关的CRUD 方法
2. 扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL
3.在 MP 全局策略中,配置 自定义注入器

自定义注入器的应用之 逻辑删除
假删除、逻辑删除: 并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据中 的一个逻辑删除字段置为删除状态. tbl_user logic_flag =1 → -1 1.com.baomidou.mybatisplus.mapper.LogicSqlInjector
2. logicDeleteValue 逻辑删除全局值
3.logicNotDeleteValue 逻辑未删除全局值
4.在 POJO 的逻辑删除字段 添加 @TableLogic 注解
5. 会在 mp 自带查询和更新方法的 sql 后面,追加『逻辑删除字段』=『LogicNotDeleteValue 默认值』 删除方法: deleteById()和其他delete 方法, 底层SQL 调用的是 update tbl_xxx set 『逻辑删除字段』=『logicDeleteValue 默认值』

以上就是
插件部分的内容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring" xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring-1.2.xsd http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

	<!-- 加载 db.properties 文件-->
	<context:property-placeholder location="classpath:db.properties"/>
	<!-- 配置数据源 -->
	<bean class="com.mchange.v2.c3p0.ComboPooledDataSource" id="dataSource">
		<property name="user" value="${jdbc.username}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="driverClass" value="${jdbc.driver}"></property>
	</bean>
	<!-- 配置SqlSessionFactoryBean -->
	<bean class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean" id="sqlSessionFactory">
		<property name="dataSource" ref="dataSource"></property>
		<!-- 给包下面所有的类别名 -->
		<property name="typeAliasesPackage" value="com.bdqn.mybatisplus.entity"></property>
		<!-- 配置映射文件路径 -->
		<property name="mapperLocations">
			<list>
				<value>classpath:mapper/*.xml</value>
			</list>
		</property>
		<!-- 全局配置 -->	
		<property name="globalConfig" ref="globalConfig"></property>
		<!-- 配置插件 -->
		<property name="plugins">
			<list>
				<!-- 配置分页插件 -->
				<bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
				<!-- 配置执行分析插件,只在开发环境中使用:修改删除过程中会查看where关键字,如果没有where关键字则不执行 -->
				<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
					<!-- 如果是全表删除或者全表修改就会停止操作 -->
					<property name="stopProceed" value="true"></property>
				</bean>
				<!-- 配置性能插件如果SQL执行超时就会抛出异常提示需要优化 -->
				<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
					<property name="maxTime" value="100"></property>
				</bean>
				<!-- 配置乐观锁插件 -->
				<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"></bean>
			</list>
		</property>
	</bean>
	<bean class="com.baomidou.mybatisplus.entity.GlobalConfiguration" id="globalConfig">
		<!-- 指定表名前缀 会自动在实体类名前面加上该值 作为表名 -->
		<property name="tablePrefix" value="tbl_"></property>
		<!-- 指定主键生成方式 0代表自增 -->
		<property name="idType" value="0"></property>
		<!-- 0是已经删除 -->
		<property name="logicDeleteValue" value="0"></property>
		<!-- 1是没有删除 -->
		<property name="logicNotDeleteValue" value="1"></property>
		<property name="sqlInjector" ref="sqlInjector"></property>
	</bean>
	
	
	<!-- 配置数据源事务管理 -->
	<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- 开启注解式务 -->
	<tx:annotation-driven transaction-manager="transactionManager"/>	
	<!-- 配置MapperScannerConfigurer -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
		<!-- 扫描包下面的接口生成代理对象 -->
		<property name="basePackage" value="com.bdqn.mybatisplus.dao"></property>
	</bean>
	<!-- 配置sql注入器 -->
	<bean class="com.baomidou.mybatisplus.mapper.LogicSqlInjector" id="sqlInjector"></bean>
	

</beans>

这就是配置的xml文件

以上就是我们MyBatisPlus的全部内容感谢观看
如有不足请在评论区指出谢谢

标签:param,entity,MyBatisPlus2,wrapper,import,new,public
来源: https://blog.csdn.net/hdnhsf/article/details/112651199

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有