文章目录

  • 1、Service层的作用
  • 2、MyBatis重要组件
    • Resources
    • SqlSessionFactoryBuilder
    • SqlSessionFactory
    • SqlSession
    • 针对上面的点,对上次的代码进行改进
  • 3、MyBatis优化开发(mybatis-config.xml)
    • 配置properties
    • 别名typeAlias
    • 映射文件mapper
  • 4、#{} 和 ${}
    • #{}
    • ${}
  • 5、插入数据并返回数据库中的主键值

1、Service层的作用

MVC = Jsp + Servlet + JavaBean
其中jsp View,servlet Controller,javaBean 是一个可复用的java对象。

BS项目
客户端发送请求 controller service dao
如果是CS项目
客户有一个界面【操作】 service dao
以上分析,BS 与 CS 的 service和dao都是一样的,这样分层,代码复用,而且容易多人协作开发。

DAO:最听话的,让你增删改你就增删改。没有情感,没有思想。
Controller:控制层,接收客户端请求的,客户端只能请求到servlet,不能请求到service,dao,其他
的java类。Controller的作用就是接收客户端请求,调用其他java类

如果要删除一个账号,谁去组织代码的逻辑呢?
这一层就是业务逻辑层,简称Service 层。
举例理解Service层

ATM机器上,你插入银行卡要给 小红 转账,1 元
【界面】转账进入转账界面输入对方的卡号输入转账金额确认按钮
【controller】可以一键生成的获取对方卡号,获取转账金额获取当前登录用户(session会话跟踪)
【service】需要程序员根据业务需求自行编写,设计规则//jdbc事务public void transfer(String fromNo,String toNo,int money){//判断对方卡号存不存在对方卡的状态对不对你的余额够不够updateMoney(toNo,1);//停电了....updateMoney(fromNo,-1);给你发短信给对方发短信给你的微信公众号发消息添加转账记录.....}
【dao】可以一键生成的public void updateMoney(String cardNo,int money);

举例2

注册账号:
【界面】填写你的账号输入两次密码手机验证码可选的(越来越多,短信不能随便发了)
【controller】 servlet(springMVC)try{接收数据 String数据封装,数据类型转换,封装为实体对象调用--》service显示结果-->请求转发/重定向到页面 或者 输出的是json}catch(Exception e){//对异常进行显示即可String msg = e.getMessage();request.setAttribute("msg",msg);//请求转发到注册jsp,jsp ${msg}//如果前端是ajax//response.getWrite().print("{result:false,msg:“+msg+”}");}
【service】业务逻辑
public void register(Account account){//判断,非空判断,长度判断,密码安全性判断【前端不是有js判断,前端判断对程序员无效】throw new RuntimeException("密码长度不足6位");//两次密码一致性判断throw new RuntimeException("两次密码不一致");//用户名or手机号是否被注册判断....//密码进行加密储存--> MD5【前端传输数据的时候就已经进行MD5的加密了】//调用dao保存数据//日志,xxx 什么 时间 xxx 注册了,什么 ip//发送短信
}
【dao】public Account queryByName(String name){}public void save(Account account){}

2、MyBatis重要组件

Resources

将文件读取为文件输入流。

//1、读取核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//2、创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

反射方式读取文件

(1)、AppClass.class.getClassLoader().getResourceAsStream("file")

从类路径classpath,也就是classes根目录下读取文件。[推荐]

//1、读取核心配置文件
//InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
InputStream in = AccountMapperTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
//2、创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

(2)、AppClass.class.getResourceAsStream(file)

// "mybatis-config.xml" 从当前类所在的包查找文件
// "/mybatis-config.xml" 从classes根目录下寻找//1、读取核心配置文件
//InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//InputStream in = AccountMapperTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
InputStream in = AccountMapperTest.class.getResourceAsStream("/mybatis-config.xml");
//2、创建SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

上述三种方式都可,在MyBatis中推荐使用Resources类。

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。

因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。

使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯“。

因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。

SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。

如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

try (SqlSession session = sqlSessionFactory.openSession()) {// 你的应用逻辑代码
}

在所有代码中都遵循这种使用模式,可以保证所有数据库资源都能被正确地关闭。

针对上面的点,对上次的代码进行改进

SqlSessionFactory设计为单例,双检查锁。

package org.westos.util;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;/*** MyBatis工具类为Mapper提供* @author lwj* @date 2020/9/3 19:43*/
public class SqlSessionFactoryUtil {private volatile static SqlSessionFactory factory;//volatile,禁止指令重排序,主要是new对象的操作private static final String CONFIG_FILE_NAME = "mybatis-config.xml";private SqlSessionFactoryUtil() {}/*** 保证SqlSessionFactory是系统唯一的* @return SqlSessionFactory*/public static SqlSessionFactory getSqlSessionFactory() {if (factory == null) {synchronized (SqlSessionFactoryUtil.class) {if (factory == null) {try {InputStream in = Resources.getResourceAsStream(CONFIG_FILE_NAME);factory = new SqlSessionFactoryBuilder().build(in);} catch (IOException e) {e.printStackTrace();}}}}return factory;}
}

AccountMapper.java

package org.westos.mapper;import org.apache.ibatis.session.SqlSession;
import org.westos.model.Account;
import org.westos.util.SqlSessionFactoryUtil;import java.util.List;/*** @author lwj* @date 2020/9/3 20:05*/
public class AccountMapper {public List<Account> queryAll() {SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession();try {return sqlSession.selectList("org.westos.mapper.AccountMapper.queryAll");} finally {sqlSession.close();}}public Account queryOne(Integer aid) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {return sqlSession.selectOne("org.westos.mapper.AccountMapper.queryOne", aid);}}public void insert(Account account) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {sqlSession.insert("org.westos.mapper.AccountMapper.insert", account);sqlSession.commit();}}public void update(Account account) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {sqlSession.update("org.westos.mapper.AccountMapper.update", account);sqlSession.commit();}}public void delete(Integer aid) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {sqlSession.delete("org.westos.mapper.AccountMapper.delete", aid);sqlSession.commit();}}
}

AccountMapper.xml

<?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="org.westos.mapper.AccountMapper"><select id="queryAll" resultType="org.westos.model.account">select aid, aname, apassword, a_nickname anicknamefrom account</select><select id="queryOne" resultType="org.westos.model.account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aid = #{aid}</select><insert id="insert">insert into account(aname, apassword, a_nickname)values(#{aname}, #{apassword}, #{anickname})</insert><update id="update">update accountset aname = #{aname}, apassword = #{apassword}, a_nickname = #{anickname}where aid = #{aid}</update><delete id="delete">delete from accountwhere aid = #{aid}</delete>
</mapper>

AccountMapperTest.java

package org.westos.test;import org.junit.Before;
import org.junit.Test;
import org.westos.mapper.AccountMapper;
import org.westos.model.Account;import java.util.List;/*** @author lwj* @date 2020/9/3 20:24*/
public class AccountMapperTest {private AccountMapper accountMapper;@Beforepublic void before() {accountMapper = new AccountMapper();}@Testpublic void queryAll() {//1、查询全部List<Account> list = accountMapper.queryAll();System.out.println(list);//[Account(aid=1, aname=zhangsan, apassword=nasgnahz, anickname=张三), Account(aid=2, aname=lisi, apassword=isil, anickname=李四)]}@Testpublic void insert() {//2、插入一条记录Account account = new Account();account.setAname("wangwu");account.setApassword("uwgnaw");account.setAnickname("王五");accountMapper.insert(account);}@Testpublic void queryOne() {//3、查询单条记录Account account = accountMapper.queryOne(3);System.out.println(account);//Account(aid=3, aname=wangwu, apassword=uwgnaw, anickname=王五)}@Testpublic void update() {//4、更新数据Account account = new Account();account.setAid(3);account.setAname("zhaoliu");account.setApassword("uiloahz");account.setAnickname("赵六");accountMapper.update(account);}@Testpublic void delete() {//5、删除记录accountMapper.delete(3);}
}

3、MyBatis优化开发(mybatis-config.xml)

配置properties

将数据库访问参数放在resources资源目录下的db.properties文件。

# 配置文件的key前面最好加上文件名
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
db.username=root
db.password=995995zxvc

在MyBatis核心配置文件中通过properties标签引入。

<!--配置-->
<properties resource="db.properties"><!--resource从classes根目录下,引入外部配置文件--><!--用EL表达式获取,${key}--><!--<property name="" value=""/>-->
</properties>

获取

<!--环境-->
<environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${db.driver}"/><property name="url" value="${db.url}"/><property name="username" value="${db.username}"/><property name="password" value="${db.password}"/></dataSource></environment>
</environments>

别名typeAlias

在XxxMapper.xml映射文件中,存在resultType配置属性,表示返回值类型。

所谓别名映射,就是简化Java类的全类名书写。

<!--别名-->
<typeAliases><!--单独一个类的别名映射--><!--<typeAlias type="org.westos.model.Account" alias="account"/>--><!--type是类型,alias是别名--><!--不足之处在于需要逐一配置--><package name="org.westos.model"/><!--对一个包下的所有类进行别名映射,别名都是类的名字,且不区分大小写-->
</typeAliases>

映射文件mapper

在mybatis-config.xml中加载了mapper.xml。

如果mapper.xml很多,引入不方便,后期会采用Mapper代理。

<!--mapper文件-->
<mappers><mapper resource="org/westos/mapper/AccountMapper.xml"/><!--<package name="org.westos.mapper"/>--><!--包扫描,加载的是Mapper接口-->
</mappers>

4、#{} 和 ${}

#{}和${}都表示参数的替换,不同之处在于:

  • #{},占位符,会根据参数的类型,自动选择是否增加单引号,本质就是利用了PreparedStatement;
  • ${}只是替换,也就是说,你传递String字符串,也是直接替换,不会为你自动增加单引号;

#{}

(1)当参数类型是简单类型时,(Java8种基本数据类型),#{}中的值可以随便编写。

(2)如果参数类型是自定义的Java类型,那么只可以编写类的属性,而且要区分大小写。

#{}使用OGNL表达式获取对象中的数据

<insert id="insert">insert into account(aname, apassword, a_nickname)values(#{aname}, #{apassword}, #{anickname})
</insert>
public void insert(Account account) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {sqlSession.insert("org.westos.mapper.AccountMapper.insert", account);sqlSession.commit();}
}

以上两个代码的结合,就是传递了Account对象,但是在SQL运行的时候,获取到了对象的属性值,这种从对象中获取属性值的方式,是通过OGNL对象图导航表达式语言完成的。

总结:#{}如果参数是非自定义对象,值可以随意填写;如果参数是自定义对象,那么值必须为属性。

#{}可以根据数据类型自动选择是否增加单引号。

${}

在mybatis-config.xml中,我们使用${}读取.properties配置文件中的值,还可以用在mapper.xml中。

将mybatis的版本修改为3.4.6,刚开始我的版本为最新版3.5.5,但是没有演示出${aid}的错误,修改版本后好了。

(1)

当参数是Integer时,#{aid}我们发现是能够获取值的。

<select id="queryOne" resultType="account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aid = #{aid}
</select>

但是,${aid}会报错,

<select id="queryOne" resultType="account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aid = ${aid}
</select>
public Account queryOne(Integer aid) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {return sqlSession.selectOne("org.westos.mapper.AccountMapper.queryOne", aid);}
}
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'aid' in 'class java.lang.Integer'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'aid' in 'class java.lang.Integer'

把Integer当做了自定义对象,寻找属性aid了,然后就会报找不到错误。

将${aid}改为${value}。

<select id="queryOne" resultType="account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aid = ${value}
</select>

成功。

与之类似的还有String类型参数。

如果参数是String类型,${aname}的情况下,把String当做了自定义对象,寻找aname属性;

org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'aname' in 'class java.lang.String'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'aname' in 'class java.lang.String'

那么此时需要改为${value};

org.apache.ibatis.exceptions.PersistenceException:
### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'lisi' in 'where clause'
### The error may exist in org/westos/mapper/AccountMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select aid, aname, apassword, a_nickname anickname         from account         where aname = lisi
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'lisi' in 'where clause'

在改为${value}后,由于${}不会为字符串类型自动添加单引号,所以还是有缺陷。

(2)

如果参数是对象类型,${对象的属性},还是通过OGNL运算给数值。

但是,${对象的属性}只是替换,不会因为你是字符串就自动给你加上单引号。

ps:所以在传递对象作为参数时,选用#{}是最好的选择。

<insert id="insert">insert into account(aname, apassword, a_nickname)values(${aname}, ${apassword}, ${anickname})
</insert>
org.apache.ibatis.exceptions.PersistenceException:
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'wangwu' in 'field list'
### The error may exist in org/westos/mapper/AccountMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: insert into account(aname, apassword, a_nickname)         values         (wangwu, uwgnaw, 王五)
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'wangwu' in 'field list'

(3)模糊查询

#{}

<!--模糊查询-->
<select id="selectByName1" resultType="account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aname like #{aname}
</select>

AccountMapper.java

//模糊查询
public List<Account> selectByName(String name) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {return sqlSession.selectList("org.westos.mapper.AccountMapper.selectByName1", name);}
}

测试方法

@Test
public void selectByName() {List<Account> list = accountMapper.selectByName("%zhang%");System.out.println(list);
}

如果使用#{},那么在参数中必须把%设置好了。

[Account(aid=1, aname=zhangsan, apassword=nasgnahz, anickname=张三)]

${}

<select id="selectByName2" resultType="account">select aid, aname, apassword, a_nickname anicknamefrom accountwhere aname like '%${value}%'
</select>

AccountMapper.java

//模糊查询
public List<Account> selectByName(String name) {try (SqlSession sqlSession = SqlSessionFactoryUtil.getSqlSessionFactory().openSession()) {return sqlSession.selectList("org.westos.mapper.AccountMapper.selectByName2", name);}
}

测试方法:

@Test
public void selectByName() {List<Account> list = accountMapper.selectByName("zhang");System.out.println(list);
}
[Account(aid=1, aname=zhangsan, apassword=nasgnahz, anickname=张三)]

但是,${}存在SQL注入的风险,慎用。

@Test
public void selectByName() {List<Account> list = accountMapper.selectByName("a' or 1 = 1 -- ");System.out.println(list);
}

最终的SQL为:

SELECT * FROM account WHERE aname LIKE '%a' OR 1 = 1 -- %';

1后面的--为SQL语言的注释。

查询结果为数据库中的所有数据:

[Account(aid=1, aname=zhangsan, apassword=nasgnahz, anickname=张三), Account(aid=2, aname=lisi, apassword=isil, anickname=李四)]

总结:${}如果参数是非自定义对象,那么值只能为value;如果参数是自定义对象,那么值必须为属性;

${}存在Sql注入的风险;

${}不会根据数据类型自动增加单引号。

5、插入数据并返回数据库中的主键值

MyBatis支持插入数据并返回数据库中的主键值。

数据库的id值存在两种情况:

  • 数据库自动维护id的值

    • sqlserver
    • mysql
  • 另一种是序列sequence
    • oracle
<!--像mysql、sqlserver,支持主键自动增长的数据库-->
<!--useGeneratedKeys:使用插入后的主键值-->
<!--keyProperty:将主键值映射到哪一属性上-->
<insert id="insert" useGeneratedKeys="true" keyProperty="aid">insert into account(aname, apassword, a_nickname)values(#{aname}, #{apassword}, #{anickname})
</insert>
@Test
public void insert() {Account account = new Account();account.setAname("wangwu");account.setApassword("uwgnaw");account.setAnickname("王五");accountMapper.insert(account);System.out.println(account.getAid());//3
}

last_insert_id()函数

<!--mysql还提供了一个函数last_insert_id(), 它必须紧跟插入语句,而且是插入语句先执行-->
<!--通过函数查询主键值,然后设置到属性中-->
<!--keyProperty:Java属性,order是指执行顺序在insert之前还是之后-->
<insert id="insert1"><selectKey keyProperty="aid" resultType="int" order="AFTER">select last_insert_id()</selectKey>insert into account(aname, apassword, a_nickname)values(#{aname}, #{apassword}, #{anickname})
</insert>
@Test
public void insert() {//2、插入一条记录Account account = new Account();account.setAname("john");account.setApassword("123456");account.setAnickname("jj");accountMapper.insert(account);System.out.println(account.getAid());//4
}

当我不想用数据库的自增长策略时,可以使用UUID函数。

MySql的函数

SELECT UUID();
<!--order先执行,uuid函数返回字符串,不能直接设置到aid字段-->
<insert id="insert2"><selectKey order="BEFORE" resultType="string" keyProperty="aname">select uuid()</selectKey>insert into account(aname, apassword, a_nickname)values(#{aname}, #{apassword}, #{anickname})
</insert>

在我第一次插入时,报data too long,原因是我的account表的aname字段只给了20个字符,但是uuid是36个字符,所以修改了下表结构。

ALTER TABLE account MODIFY COLUMN aname VARCHAR(50);
@Test
public void insert() {//2、插入一条记录Account account = new Account();account.setAname("kenny");account.setApassword("123456");account.setAnickname("kk");accountMapper.insert(account);System.out.println(account.getAname());//cef4cf5e-ee6b-11ea-8661-98fa9b26cec1
}

3、JavaWeb中Service层的作用、MyBatis的重要组件、mybatis-config.xml中的别名映射、properties配置、#{}和${}的区别、获取插入数据的主键值相关推荐

  1. MyBatis框架——mybatis插入数据返回主键(mysql、oracle)

    向数据库中插入数据时,大多数情况都会使用自增列或者UUID做为主键.主键的值都是插入之前无法知道的,但很多情况下我们在插入数据后需要使用刚刚插入数据的主键,比如向两张关联表A.B中插入数据(A的主键是 ...

  2. 中service层的作用_浅析Java中dto、dao、service、controller的四层结构

    目前我所在的项目组采用的是SpringBoot框架,前端使用BootStrap+jQuery. SpringBoot是BS开发框架之一,不用单独开启tomcat服务器,目前比较流行,一般开发大型项目时 ...

  3. mybatis中useGeneratedKeys用法--插入数据库后获取主键值

    前言:今天无意在mapper文件中看到useGeneratedKeys这个词,好奇就查了下,发现能解决我之前插入有外键表数据时,这个外键获取繁琐的问题,于是学习敲DEMO记录    在项目中经常需要获 ...

  4. mybatis mysql usegeneratedkeys_mybatis中useGeneratedKeys用法--插入数据库后获取主键值

    前言:今天无意在mapper文件中看到useGeneratedKeys这个词,好奇就查了下,发现能解决我之前插入有外键表数据时,这个外键获取繁琐的问题,于是学习敲DEMO记录 在项目中经常需要获取到插 ...

  5. MyBatis 插入数据库返回主键

    最近在搞一个电商系统中由于业务需求,需要在插入一条产品信息后返回产品Id,刚开始遇到一些坑,这里做下笔记,以防今后忘记. 类似下面这段代码一样获取插入后的主键 User user = new User ...

  6. service层的作用

    一直不太明白service层的作用,有时候甚至感觉service层可有可无. dao层中已经有操作数据库的方法了,为什么还要service层去封装?有什么好处? 首先是mvc三层架构 mvc三层架构 ...

  7. caffe中各层的作用

    caffe中各层的作用: 关于caffe中的solver: cafffe中的sover的方法都有: Stochastic Gradient Descent (type: "SGD" ...

  8. service层的作用是什么?是否可以省略

    一个基本的java项目分成Controller层,service层,mapper层等,controller是控制器层,mapper是数据访问层,与数据库相关,进行对数据库的增删改查等操作,servic ...

  9. MyBatis 获取数据库中自增主键值

    一.在 SQL 映射文件的 select 标签中添加 useGeneratedKeys="true" 属性与 keyProperty=" " 属性,keyPro ...

最新文章

  1. 台式计算机不能有线上网,台式电脑怎么样不能有线就可以连接网络,赶紧看看...
  2. Codeforces Round #504 E - Down or Right 交互题
  3. log4j配置文件_Mybatis对log4j的支持及常用标签-Mybatis(6)
  4. QT的QDrag类的使用
  5. 数据仓库分层和元数据管理
  6. 互联网医生-ICMP协议
  7. Ssm框架实现的学生信息管理系统
  8. python主要用来做什么-python语言都可以做什么
  9. WebWorker和Server-Sent Events和HTML5 WebSocket
  10. javascript基础(对象继承与引用)
  11. android 动态获取权限
  12. xtdpdgmm:动态面板数据模型一网打尽
  13. 利用matlab实现h 控制,利用matlab实现H-infinity鲁棒控制.doc
  14. 昨日皇者——Symbian(塞班)
  15. Math常用的数学运算(包括取整、取绝对值、保留几位小数等)
  16. proc report过程步
  17. c语言中函数值类型的定义,C语言允许函数值类型缺省定义,此时该函数值隐含的类型是( )。(A)float (B)int (C)long (D)double...
  18. Mac系统关闭体统提示升级
  19. win8.1快捷操作集合
  20. Ubuntu18.04

热门文章

  1. MagicBook屏幕频闪解决方案(Windows、MacOS)
  2. 对手机网络状态改变时的监听
  3. HTG评论The Wink Hub:在不破坏资金的情况下为您的智能家居提供大脑
  4. 2022IYPT/CUPT第十一题 旋风球(橡皮筋上的球)
  5. 名词介绍 CAPEX OPEX
  6. Laravel本地Sail开发环境下Phpstorm+浏览器+Postman调试配置
  7. 哈工大软件构造课程知识点总结(一)
  8. mysql 按月和年累加_2020年5月播出的电视剧汇总,按时间先后顺序排列
  9. android屏幕适配之点9图片
  10. netty的IM项目小结