动力节点—2020最新MyBatis教程笔记
文章目录
- 1 介绍
- 2 快速入门
- 2.1 操作步骤(P9)
- 2.1.1 首先创建maven
- 2.1.2 接着会做一些配置
- 2.2 在编译的target目录下面缺少xml的解决方式(P11)
- 2.3 日志的输出
- 2.4 注意事项
- 2.5对各个对象的分析
- Resource类
- SqlSessionFactoryBuilder类
- SqlSessionFactory接口
- SqlSession接口
- 2.6 工具类
- 3 MyBatis DAO代理
- 3.1两种sql的执行方式
- 3.2 参数的理解
- 3.2.1 parameterType
- 3.2.2 传入的参数在SQL语句中的使用
- 3.2.3 #和$的区别
- 3.2.4 resultType和resultMap
- 3.2.5 模糊like
- 4 动态SQL
- 4.1 if 和 where
- 4.2 foreach
- 4.3 代码片段,重用
- 5 配置文件
- 5.1 主配置文件
- 5.2 dataSource
- 5.3 事务
- 5.4 使用数据库属性配置文件
- 5.5 mapper(映射器)
- 6 分页
本文为动力节点2020MyBatis笔记整理,视频地址为https://www.bilibili.com/video/BV185411s7Ry?from=search&seid=5830402177484068371。
王鹤老师的笔记可自行去动力节点官网下载。
1 介绍
Java WEB 通常分为三层,即表示层,业务逻辑层,数据访问层。
三层的职责
界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库
具体过程为:用户—> 界面层(Spring MVC)—>业务逻辑层(Spring)—>数据访问层(MyBatis)—>DB 数据库。
MyBatis 框架:
MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。
MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
2 快速入门
对于MyBatis项目来说,除了maven本身的pom.xml以外,还有主配置文件mybatis-config.xml,通常放在Resource目录下;以及各个Dao接口对应的在同级目录下且同名的xml映射文件。在主配置文件中,可以设置数据源,事务,别名,日志,分页以及映射器位置,在Dao对应的映射文件中,通常是写相应的SQL语句来实现Dao的各种功能。
2.1 操作步骤(P9)
2.1.1 首先创建maven
(1)创建maven:New Project/Module->选择Maven,打钩Create from archetype,选择 :maven-archetype-quickstart,next->输入Name/Location,点开Artifact Coordinates,输入相应Id。
(2)等待加载完成后,在src/main上右击,产生resources目录,resources下面的资源在编译后在target/classes下面。
2.1.2 接着会做一些配置
(1)在pom.xml中,修改properties中的1.7为1.8,删除maven原有的build,加入maven的依赖,包括mybatis和mysql驱动,以及一个扫描src/main/java目录下的各种资源放入编译后的target下的classes
<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.9</version></dependency>
</dependencies><build><resources><resource><directory>src/main/java</directory><!--所在的目录--><includes><!--包括目录下的.properties,.xml 文件都会扫描到--><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins>
</build>
(2)创建Dao接口以及涉及到的Bean对象
(3)创建mapper文件,也叫sql映射文件,是一个xml:写sql语句的,和接口中方法对应的sql语句。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.dao.StudentDao"><!--select:表示查询操作。id: 你要执行的sql语法的唯一标识, mybatis会使用这个id的值来找到要执行的sql语句可以自定义,但是要求你使用接口中的方法名称。resultType:表示结果类型的, 是sql语句执行后得到ResultSet,遍历这个ResultSet得到java对象的类型。值写的类型的全限定名称--><select id="selectStudents" resultType="com.bjpowernode.domain.Student">select id,name,email,age from student order by id</select><!--插入操作--><insert id="insertStudent">insert into student values(#{id},#{name},#{email},#{age})</insert>
</mapper>
<!--sql映射文件(sql mapper): 写sql语句的, mybatis会执行这些sql1.指定约束文件<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">mybatis-3-mapper.dtd是约束文件的名称, 扩展名是dtd的。2.约束文件作用: 限制,检查在当前文件中出现的标签,属性必须符合mybatis的要求。3.mapper 是当前文件的根标签,必须的。namespace:叫做命名空间,唯一值的, 可以是自定义的字符串。要求你使用dao接口的全限定名称。4.在当前文件中,可以使用特定的标签,表示数据库的特定操作。<select>:表示执行查询,select语句<update>:表示更新数据库的操作, 就是在<update>标签中 写的是update sql语句<insert>:表示插入, 放的是insert语句<delete>:表示删除, 执行的delete语句
-->
(4)创建mybatis的一个主配置文件,也是xml,放在resources下,1)连接数据库;2)指定mapper文件的位置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--settings:控制mybatis全局行为--><settings><!--设置mybatis输出日志--><setting name="logImpl" value="STDOUT_LOGGING" /></settings><!--环境配置: 数据库的连接信息default:必须和某个environment的id值一样。告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库--><environments default="mydev"><!-- environment : 一个数据库信息的配置, 环境id:一个唯一值,自定义,表示环境的名称。--><environment id="mydev"><!--transactionManager :mybatis的事务类型type: JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)--><transactionManager type="JDBC"/><!--dataSource:表示数据源,连接数据库的type:表示数据源的类型, POOLED表示使用连接池--><dataSource type="POOLED"><!--driver, user, username, password 是固定的,不能自定义。--><!--数据库的驱动类名--><property name="driver" value="com.mysql.jdbc.Driver"/><!--连接数据库的url字符串--><property name="url" value="jdbc:mysql://localhost:3306/springdb"/><!--访问数据库的用户名--><property name="username" value="root"/><!--密码--><property name="password" value="root"/></dataSource></environment></environments><!-- sql mapper(sql映射文件)的位置--><mappers><!--一个mapper标签指定一个文件的位置。从类路径开始的路径信息。 target/clasess(类路径)--><mapper resource="com/bjpowernode/dao/StudentDao.xml"/><!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />--></mappers>
</configuration>
<!--mybatis的主配置文件: 主要定义了数据库的配置信息, sql映射文件的位置1. 约束文件<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">mybatis-3-config.dtd:约束文件的名称2. configuration 根标签。
-->
(5)使用mybatis的对象SqlSession,通过他的方法执行sql语句。
@Test
public void testSelect() throws Exception{//1.mybatis 主配置文件String config = "mybatis-config.xml";//2.读取配置文件InputStream in = Resources.getResourceAsStream(config);//3.创建 SqlSessionFactory 对象,目的是获取 SqlSessionSqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);//4.获取 SqlSession,SqlSession 能执行 sql 语句SqlSession session = factory.openSession();//5.执行 SqlSession 的 selectList()List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");//6.循环输出查询结果studentList.forEach( student -> System.out.println(student));//7.关闭 SqlSession,释放资源session.close();
}
2.2 在编译的target目录下面缺少xml的解决方式(P11)
事先做的配置
1.resource文件夹,前面需要有相应的标识,没有的话,右键-Mark Directory as
2.在pom.xml文件中的<build><resources>…</resources></build>放置resource,用于扫描并将src/main/java的相应资源导入。(见操作步骤)
解决方式
1.右边的maven,先clean,然后compile
2.上面的Build-ReBuild Project
3.上边的File-Invalidate Caches/Restart,再点一次。
4.将sql映射文件和主配置文件直接拷贝到target目录下面。
2.3 日志的输出
在mybatis.xml的<configuration>后面添加
<settings><setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
2.4 注意事项
mybatis默认非自动提交事务,查询不需要提交,而insert/update/delete,需要提交,sqlSession.commit();
2.5对各个对象的分析
Resource类
Resources 类,顾名思义就是资源,用于读取资源文件。其有很多方法通过加载并解析资源文件,返回不同类型的 IO 流对象。
SqlSessionFactoryBuilder类
SqlSessionFactory 的 创 建 , 需 要 使 用 SqlSessionFactoryBuilder 对 象 的 build() 方 法 。 由于SqlSessionFactoryBuilder 对象在创建完工厂对象后,就完成了其历史使命,即可被销毁。所以,一般会将该 SqlSessionFactoryBuilder 对象创建为一个方法内的局部对象,方法结束,对象销毁。
SqlSessionFactory接口
SqlSessionFactory 接口对象是一个重量级对象(系统开销大的对象),是线程安全的,所以一个应用只需要一个该对象即可。创建 SqlSession 需要使用 SqlSessionFactory 接口的的 openSession()方法。
➢ openSession(true):创建一个有自动提交功能的 SqlSession
➢ openSession(false):创建一个非自动提交功能的 SqlSession,需手动提交
➢ openSession():同 openSession(false)
SqlSession接口
SqlSession 接口对象用于执行持久化操作。一个 SqlSession 对应着一次数据库会话,一次会话以SqlSession 对象的创建开始,以 SqlSession 对象的关闭结束。
SqlSession 接口对象是线程不安全的,所以每次数据库会话结束前,需要马上调用其 close()方法,将其关闭。再次需要会话,再次创建。 SqlSession 在方法内部创建,使用完毕后关闭。
2.6 工具类
通过该工具类的静态方法可以方便获取SqlSession。
public class MyBatisUtils {private static SqlSessionFactory factory = null;static {String config="mybatis.xml"; // 需要和你的项目中的文件名一样try {InputStream in = Resources.getResourceAsStream(config);//创建SqlSessionFactory对象,使用SqlSessionFactoryBuildfactory = new SqlSessionFactoryBuilder().build(in);} catch (IOException e) {e.printStackTrace();}}//获取SqlSession的方法public static SqlSession getSqlSession() {SqlSession sqlSession = null;if( factory != null){sqlSession = factory.openSession();// 非自动提交事务}return sqlSession;}
}
3 MyBatis DAO代理
3.1两种sql的执行方式
第一类是前面的方法,SqlSession直接执行selectList/update/delete/insert之类操作;
第二类是先通过SqlSession的getMapper()获取接口Dao的实现类,然后调用接口的方法。原理是动态代理。
以select为例解释,第一种是通过SqlSession直接执行selectList来获取数据,第二种是SqlSession首先获取一个StudentDao的一个实现类,该实现类可以直接调用selectStudents获取数据。
SqlSession session = MyBatisUtil.getSqlSession();
List<Student> studentList = session.selectList("com.bjpowernode.dao.StudentDao.selectStudents");StudentDao studentDao = MyBatisUtil.getSqlSession().getMapper(StudentDao.class);
List<Student> studentList = studentDao.selectStudents();
3.2 参数的理解
3.2.1 parameterType
parameterType表示传入的参数类型,可以省略。
3.2.2 传入的参数在SQL语句中的使用
(1)如果传入的是一个简单类型(java 基本类型和 String),在SQL中,可以用#{任意字符}
<select id="selectById" resultType="com.bjpowernode.domain.Student">select id,name,email,age from student where id=#{studentId}
</select>
#{studentId} , studentId 是自定义的变量名称,和方法参数名无关。
(2)传入多个参数,使用@Param
接口方法:
List<Student> selectMultiParam(@Param("personName") String name,@Param("personAge") int age);mapper 文件:
<select id="selectMultiParam" resultType="com.bjpowernode.domain.Student">select id,name,email,age from student where name=#{personName} or age
=#{personAge}</select>
(3)传入一个对象,#{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 },简写为 #{ property }
创建保存参数值的对象 QueryParam
package com.bjpowernode.vo;
public class QueryParam {private String queryName;private int queryAge;//set ,get 方法}接口方法:
List<Student> selectMultiObject(QueryParam queryParam);mapper 文件:
<select id="selectMultiObject" resultType="com.bjpowernode.domain.Student">select id,name,email,age from student where name=#{queryName} or age
=#{queryAge}
</select>
(4)多个参数还可以按位置或者使用map
3.2.3 #和$的区别
1. #使用 ?在sql语句中做占位的, 使用PreparedStatement执行sql,效率高2. #能够避免sql注入,更安全。3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低4. $有sql注入的风险,缺乏安全性。5. $:可以替换表名或者列名
3.2.4 resultType和resultMap
两者选一,resultMap主要用于表的列和对象属性不匹配。
<resultMap id="student2Map" type="com.bjpowernode.domain.Student2"><!-- 主键字段使用 id --><id column="id" property="id2" /><!--非主键字段使用 result--><result column="name" property="name2"/><result column="email" property="email2" /><result column="age" property="age2" />
</resultMap><select id="selectStudents2" resultMap="student2Map">select id,name,email,age from student order by id
</select>
3.2.5 模糊like
例 1: java 代码中提供要查询的 “%力%”
接口方法:
List<Student> selectLikeFirst(String name);
mapper 文件:
<select id="selectLikeFirst" resultType="com.bjpowernode.domain.Student">select id,name,email,age from studentwhere name like #{studentName}
</select>
测试方法:
@Test
public void testSelectLikeOne(){String name="%力%";List<Student> stuList = studentDao.selectLikeFirst(name);stuList.forEach( stu -> System.out.println(stu));
}
例 2:mapper 文件中使用 like name “%” #{xxx} “%”
接口方法:
List<Student> selectLikeSecond(String name);
mapper 文件:
<select id="selectLikeSecond" resultType="com.bjpowernode.domain.Student">select id,name,email,age from studentwhere name like "%" #{studentName} "%"
</select>
测试方法:
@Test
public void testSelectLikeSecond(){String name="力";List<Student> stuList = studentDao.selectLikeSecond(name);stuList.forEach( stu -> System.out.println(stu));
}
4 动态SQL
对于 sql 中的"<",一定要换成"<"。
动态 SQL 相当于会变化的 SQL,主要包括<if>,<where>,<foreach>和代码片段。
if 可以在满足条件时执行相应功能,where主要用于包装if,去掉多余的and/or,foreach是对于一个可以遍历的集合进行输出,代码片段表示代码的重用功能。
示例:
4.1 if 和 where
<select id="selectStudentWhere" resultType="com.bjpowernode.domain.Student">select id,name,email,age from student<where><if test="name != null and name !='' ">and name = #{name}</if><if test="age > 0 ">and age > #{age}</if></where>
</select>
4.2 foreach
<!--说明-->
<foreach collection="集合类型" open="开始的字符" close="结束的字符"
item="集合中的成员" separator="集合成员之间的分隔符">#{item 的值}
</foreach><!--示例-->
<select id="selectStudentForList"
resultType="com.bjpowernode.domain.Student">select id,name,email,age from student<if test="list !=null and list.size > 0 ">where id in<foreach collection="list" open="(" close=")"
item="stuid" separator=",">#{stuid}</foreach></if>
</select>
4.3 代码片段,重用
<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用<include/>子标签。
<sql id="studentSql">select id,name,email,age from student
</sql> <select id="selectStudentSqlFragment"
resultType="com.bjpowernode.domain.Student"><!-- 引用 sql 片段 --><include refid="studentSql"/><if test="list !=null and list.size > 0 ">where id in<foreach collection="list" open="(" close=")"
item="stuobject" separator=",">#{stuobject.id}</foreach></if>
</select>
5 配置文件
5.1 主配置文件
之前项目中使用的 mybatis.xml 是主配置文件。
主配置文件特点:
1.xml 文件,需要在头部使用约束文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
2.根元素,<configuration>
3.主要包含内容:
定义别名
数据源
mapper 文件
5.2 dataSource
在主配置文件中配置,包括下面三种
UNPOOLED 不使用连接池的数据源,MyBatis 会创建 UnpooledDataSource 实例
POOLED 使用连接池的数据源,MyBatis 会创建 PooledDataSource 实例
JNDI 使用 JNDI 实现的数据源,MyBatis 会从 JNDI 服务上查找 DataSource 实例
<dataSource type="POOLED"><!--连接数据库的四个要素--><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url"
value="jdbc:mysql://localhost:3306/ssm?charset=utf-8"/><property name="username" value="root"/><property name="password" value="123456"/>
</dataSource>
5.3 事务
使用位置,<transactionManager type=“JDBC”/>
JDBC,使用 JDBC 的事务管理机制。默认不自动提交,需要手动提交。
MANAGED,由容器来管理事务的整个生命周期(如 Spring 容器)。
5.4 使用数据库属性配置文件
将写在dataSource中数据库四个要素抽取到一个文件中,主文件中换成${文件名.具体name}。
<dataSource type="POOLED"><!--使用 properties 文件: 语法 ${key}--><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/>
</dataSource>
5.5 mapper(映射器)
1.<mapper resource=" " />
使用相对于类路径的资源,从 classpath 路径查找文件,
例如:<mapper resource=“com/bjpowernode/dao/StudentDao.xml” />
2. <package name=""/>
指定包下的所有 Dao 接口
如:<package name=“com.bjpowernode.dao”/>
注意:此种方法要求 Dao 接口名称和 mapper 映射文件名称相同,且在同一个目录中。
6 分页
使用插件 PageHelper,对应配置如下:
- 在pom.xml中
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version>
</dependency>
- 在mybatis主配置文件中,<environments>之前加入
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
用法
@Test
public void testSelect() throws IOException {//获取第 1 页,3 条内容PageHelper.startPage(1,3);List<Student> studentList = studentDao.selectStudents();studentList.forEach( stu -> System.out.println(stu));
}
动力节点—2020最新MyBatis教程笔记相关推荐
- 动力节点—2020最新Spring教程笔记(上)
文章目录 1 Spring 概述 2 IOC 控制反转 2.1 基于XML的DI 2.1.1 注入分类 2.1.1.1 set注入 2.1.1.2 构造注入(了解) 2.1.2 自动注入 2.2 基于 ...
- (B站动力节点老杜MySQL教程)MySQL课堂笔记-day01.txt
文章目录 文件来源/资料下载: MySQL课堂笔记-day01.txt 1.sql.DB.DBMS分别是什么,他们之间的关系? 2.什么是表? 3.学习MySQL主要还是学习通用的SQL语句,那么SQ ...
- (B站动力节点老杜MySQL教程)MySQL课堂笔记-day03.txt
文章目录 文件来源/资料下载: MySQL课堂笔记-day03.txt 1.约束 1.1.唯一性约束(unique) 1.2.主键约束 1.3.外键约束 2.存储引擎?(整个内容属于了解内容) 2.1 ...
- (B站动力节点老杜MySQL教程)MySQL课堂笔记-day02.txt
文章目录 文件来源/资料下载: MySQL课堂笔记-day02.txt 1.关于查询结果集的去重? 2.连接查询 2.1.什么是连接查询? 2.2.连接查询的分类? 2.3.在表的连接查询方面有一种现 ...
- Xmind软件 2020最新安装教程讲解
Xmind 2020最新安装教程 1. 首先需要下载Xmind软件(百度网盘链接附上) 2.安装步骤直接就是双击下载好的软件安装即可 3. 安装成功后找到xmind安装目录下的resource目录替换 ...
- 动力节点Git安装使用教程,详细到哭
Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效.高速的处理从很小到非常大的项目版本管理.Git是Linux作者Linus Torvalds为了帮助管理Linux内核开发而开发的一个 ...
- 2020最新Python入门笔记,建议收藏
Python变量和数据类型 数据类型 print语句 注释 Python的注释以 # 开头,后面的文字直到行尾都算注释 # 这一行全部都是注释... print 'hello' # 这也是注释 这里要 ...
- Spring动力节点老杜课程学习笔记
没有Spring的时候我们如何进行开发的? 没有Spring为我们服务的,写代码一定是这样的 调用层: public static void main(String[] args) {//创建视图层对 ...
- 2020最新SpringMVC教程【IDEA版】-springmvc从入门到精通
2021-06-28 思维导图 1/74p SpringMVC Web开发底层是servlet 2/74p SpringMVC Web开发步骤 3/74p SpringMVC 中央调度器创建sprin ...
最新文章
- 挖矿的电费自由日——矿工为何每个月总有那么几十天闷闷不乐
- Service应用场景分析
- percona server修改数据目录datadir为/data/mysql:
- 讨论UML概念和模型UML九种图。
- redis 高级特性一
- 广义的B端产品人,都是什么职位?
- uni-app微信小程序登录授权
- 做系统ghost步骤图解_u盘装系统步骤
- 真假黄仁勋疑云?英伟达推出全球首个元宇宙平台
- 算法设计与分析(第2版)屈婉玲 刘田 张立昂 王捍贫编著 第二章课后习题答案
- ap6212linux驱动下载,AP6212各个版本固件
- 惯量比多少合适_惯量比计算公式
- word复制某一页并插入到新页
- qqc什么梗_网络语cpdd是什么意思 王者荣耀QQ飞车里很常见
- wpf 点击按钮弹出新对话框_WPF学习弹出新窗口
- 怎么把计算机隐藏文件显示出来,怎么把隐藏的文件夹显示出来
- 一代JS代码可以搞定机器自动刷票,投票页数据验证很重要
- python后面空格报错_python空格报错
- 英特尔多核平台编码优化大赛就顺便试试身手了
- node+express实现文件上传功能
热门文章
- 记录getElementsByTagName()
- 115一直正在连接服务器失败怎么办,TCP连接错误115正在进行操作原因是什么?
- python控制台小游戏_学习编程的好方法——控制台游戏
- 医疗信息化的第二春天是什么
- 《Whale 帷幄隐私保护白皮书》重磅发布!
- binlog数据库不写入binlog_mysql在不开启binlog的情况下导出数据库
- ansible playbook脚本获取系统版本信息
- 计算机心理部的活动记录表,心理部工作总结的参考范文
- 我用过的最好的python编辑器PyScripter
- 自学Java 推荐视频资源