快速上手MyBatis-Plus
什么是Mybatis-Plus
是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变
MyBatis Puls 优点 :
- 无需提供sql 增删改查操作
- 内置代码生成器 分页插件等
- 提供功能丰富的条件构造器快速无sql开发
- 做一些中小项目 开发效率快
缺点 :
- 大项目 分布式项目 效率慢
快速入门
导入相关依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version> </dependency> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> </dependency> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId> </dependency>
进行四要素配置
spring.datasource.url=jdbc:mysql://localhost:3306/mp?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true spring.datasource.username=root spring.datasource.password=admin spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 配置slq打印日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
创建mapper,继承BaseMapper<.T>接口,无需写映射文件
@Repository public interface EmployeeMapper extends BaseMapper<Employee> {}
创建自定义service接口,继承IService<.T>接口
创建service实现类,继承ServiceImpl<实体对象对应mapper接口,实体类对象>,并且实现自定义接口
public interface IEmployeeService extends IService<Employee> {}
@Service public class EmployeeService extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService{}
在启动容器时需进行包扫描
@MapperScan(basePackages = "cn.kjcoder.mp.mapper")
测试
@SpringBootTest public class CrudTest {@Autowiredprivate EmployeeMapper employeeMapper;@Testpublic void selectList(){List<Employee> employees = employeeMapper.selectList(null);System.out.println(employees);} }
代码结构:
public interface UserMapper extends BaseMapper<User>{}public interface IUserService extends IService<User>{}public class UserServiceImpl extends ServiceImpl<UserMapper,User > implements IUserService{}
思考
★问题1:EmployeeMapper并没有定义crud方法,为什么在测试类可以直接用呢?*
EmployeeMapper 继承了BaseMapper接口,自然可以使用父类BaseMapper接口定义crud方法了
★项目中并没有写crud sql语句,为什么可以执行crud 操作呢?
★mybatis-plus原理
mybatis-plus 自动拼接了sql,观察发现,表名跟mapper接口操作实体对象类名一样,列名跟mapper接口操作的实体对象属性名一样,那么可以使用java中的内省机制和反射,将实体对象的类解析得到类名做表名,属性字段做列名,将得到的表名和列名自动拼接成sql语句并注入到mybatis容器中
常用注解
@TableName(xxxx)
:作用在类上,当表名与类名不一致时用于映射当前类对应的表名,默认跟实体类名一致
@TableId(value="id", type= IdType.AUTO)
:作用在类的字段上,指定类型为自增长id策略
@TableField(value="ename")
:作用在类的字段上,当类中的属性名与表中的字段名称不一致,用此注解进行映射
@TableField(exist = false)
:作用在类的字段上,表示当前的属性不参与sql拼接和列的映射
打印日志
方式一:
logging.level.cn.kjcoder.mp.mapper=debug
方式二:
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
Mapper接口方法
保存
insert(domain)
/*** 插入一条记录* INSERT INTO employee ( name, password, email, age, admin, dept_id ) VALUES ( ?, ?, ?, ?, ?, ? )*/
Employee employee = new Employee();
employee.setName("lisa");
employee.setPassword("123455");
employee.setEmail("lisa@qq.com");
employee.setAge(20);
employee.setDeptId(2L);
employee.setAdmin(0);
employeeMapper.insert(employee);
更新
updateById(domain)
:如果要更新的domain对象属性值为null,该属性值不参与sql拼接,如果是非null字段,mybatis-plus认为有值,就参与sql拼接
解决方案:
- 将基本数据类型改为包装类型
/*** 将id=1用户名字修改为hkj* UPDATE employee SET name=?, age=?, admin=? WHERE id=?*/
Employee employee = new Employee();
employee.setId(1L);
employee.setName("gd");
employeeMapper.updateById(employee);
- 先查询,在设置,最后再更新
/*** UPDATE employee SET name=?, password=?, email=?, age=?, admin=?, dept_id=? WHERE id=?*/
Employee employee = employeeMapper.selectById(1L);
employee.setName("hkj");
employeeMapper.updateById(employee);
- 使用update(null,wrapper)方法
update(null,Wrapper)
:使用自定义update方式的sql语句进行部分字段更新
/*** 更新name=hkj员工年龄为18岁* UPDATE employee SET age=? WHERE (name = ?)*/
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("name","hkj");
wrapper.set("age",18);
employeeMapper.update(null,wrapper);
***选用问题:***如果更新条件是id,并且是更新所有字段,使用updateById
如果只需更新部分字段,使用update
saveOrUpdate(domain,UpdateWapper)
:
当是主键自动生成的数据,一定要写UpdateWrapper,不然你必然是一直插入!完全不会进行更新,因为默认是用id查询的,当saveOrUpdate不使用条件构造器时,会先做根据主键查询,如果查出来的结果为0,那么就执行插入操作,如果查出来的结果不为0,则执行更新操作。
删除
deleteById(Serializable id)
/*** 删除id=21的员工信息* DELETE FROM employee WHERE id=?*/
employeeMapper.deleteById(21L);
deleteBatchIds(Collection)
:批量删除,类似sql语句中的in条件
/*** 删除id=1, id=2的员工信息* DELETE FROM employee WHERE id IN ( ? , ? )*/
employeeMapper.deleteBatchIds(Arrays.asList(1L,2L));
deleteByMap(Map)
:删除指定属性值的对象,map中的key为数据库字段名,value为字段值
/*** 删除name=xiaofei并且age=0的员工信息* DELETE FROM employee WHERE name = ? AND age = ?*/
Map<String,Object> map = new HashMap<>();
map.put("name","xiaofei");
map.put("age",0);
employeeMapper.deleteByMap(map);
delete(Wrapper)
:Wrapper用于指定要删除的条件
/*** 删除name=李六明并且age=25的员工信息* DELETE FROM employee WHERE (name = ? AND age = ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","李六明").eq("age",25);
employeeMapper.delete(wrapper);
查询
selectById(Serializable id)
/*** 查询id=3的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE id=?*/
Employee employee = employeeMapper.selectById(3L);
selectBatchIds(Collection)
:批量查询,类似sql语句中的in条件
/***查询id=3,id=4的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE id IN ( ? , ? )*/
List<Employee> employees = employeeMapper.selectBatchIds(Arrays.asList(3L, 4L));
selectByMap(Map)
:查询指定属性值的对象,map中的key是列名,value是对应的值
/*** 查询name=yoonas, age=18的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE name = ? AND age = ?*/
Map<String,Object> map = new HashMap<>();
map.put("name", "yoonas");
map.put("age",18);
List<Employee> employees = employeeMapper.selectByMap(map);
selectCount(Wrapper)
/*** 查询满足条件的所有的员工个数* SELECT COUNT( 1 ) FROM employee WHERE (age = ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
//employeeMapper.selectCount(null);
wrapper.eq("age",18);
Integer count = employeeMapper.selectCount(wrapper);
selectList(Wrapper)
/*** 查询满足条件的所有的员工信息, 返回List<Employee>* SELECT id,name,password,email,age,admin,dept_id FROM employee*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
//employeeMapper.selectList(null);
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
selectMaps(Wrapper)
:返回值为List<Map<String, Object>>,如果查询的数据无法封装成对象就使用该方法,类似查询的sql中含有group by…
/*** 查询满足条件的所有的员工信息, 返回List<Map<String, Object>>* SELECT id,name,password,email,age,admin,dept_id FROM employee*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
List<Map<String, Object>> maps = employeeMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
selectOne
/*** 查询name为yoonas的记录* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name","yoonas");
Employee employee = employeeMapper.selectOne(wrapper);
分页
selectPage(Page,Wrapper)
要想实现分页效果,需要在启动类中配置分页拦截器
//分页拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);paginationInnerInterceptor.setOverflow(true); //合理化interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor;
}
@Test
public void testSelectPage(){QueryWrapper<Employee> wrapper = new QueryWrapper<>();//参数1:当前页, 参数2:每页显示条数IPage<Employee> page = new Page<>(2,3);employeeMapper.selectPage(page,wrapper);System.out.println("当前页:" + page.getCurrent());System.out.println("每页显示条数:" + page.getSize());System.out.println("总页数:" + page.getPages());System.out.println("总数:" + page.getTotal());System.out.println("当前页数据:" + page.getRecords());
}
编写分页逻辑代码
//service
@Override
public IPage<Employee> query(QueryObject qo) {IPage<Employee> page = new Page<>(qo.getCurrentPage(),qo.getPageSize());QueryWrapper<Employee> wrapper = new QueryWrapper<>();return super.page(page,wrapper);
}
//controller
@Test
public void testQuery(){QueryObject qo = new QueryObject();qo.setCurrentPage(2);qo.setPageSize(3);IPage<Employee> page = employeeService.query(qo);System.out.println("当前页:" + page.getCurrent());System.out.println("总页数:" + page.getPages());System.out.println("每页显示条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("当前页显示记录:" + page.getRecords());
}
条件构造器
可以简单理解为用于生成mybatis动态sql或sql语句片段(<sql.><./sql>)
更新操作
UpdateWrapper方式:
set:
/*** 将id=3的员工age改为18, 如果传入username变量值不等于null或者“”,修改为员工name为username变量值* UPDATE employee SET age=?,name=? WHERE (id = ?)*/
String username = "angle";
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 3L);
wrapper.set("age",18);
if(StringUtils.hasLength(username)){wrapper.set("name",username);
}
employeeMapper.update(null,wrapper);
setSql:
/*** 将id=3的用户name改为yoona* UPDATE employee SET name = 'yoona' WHERE (id = ?)*/
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",3L);
wrapper.setSql("name = 'yoona'");
employeeMapper.update(null,wrapper);
LambdaUpdateWrapper方式:
/*** 将id=3的用户name改为hkj* UPDATE employee SET name=? WHERE (id = ?)*/
LambdaUpdateWrapper<Employee> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(Employee::getId,3);
wrapper.set(Employee::getName,"hkj");
employeeMapper.update(null,wrapper);
查询操作
/** 普通查询* 查询name=dafei, age=18的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE name = ? AND age = ?*/
Map<String,Object> map = new HashMap<>();
map.put("name", "dafei");
map.put("age",18);
List<Employee> employees = employeeMapper.selectByMap(map);
/** QueryWrapper查询* 查询name=dafei, age=18的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ? AND age = ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.eq("name", "dafei");
wrapper.eq("age",18);
List<Employee> employees = employeeMapper.selectList(wrapper);
/** LambdaQueryWrapper查询* 查询name=dafei, age=18的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name = ? AND age = ?)*/
LambdaQueryWrapper<Employee> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Employee::getName,"dafei").eq(Employee::getAge,18);
List<Employee> employees = employeeMapper.selectList(wrapper);
高級查询
列投影
/**列投影* :查询所有员工, 返回员工name, age列* SELECT name,age FROM employee*/
ueryWrapper<Employee> wrapper = new QueryWrapper<>();
//wrapper.select("name,age");
wrapper.select("name","age");
List<Employee> employees = employeeMapper.selectList(wrapper);
/**列投影* 查询所有员工, 返回员工表中以h字母开头的列*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.select(Employee.class,columnValue->columnValue.getProperty().startsWith("h"));
List<Employee> employees = employeeMapper.selectList(wrapper);
/*** 根据id查询某个用户的指定字段* SELECT id,nick_name,parent_id FROM qr_member WHERE (id = ?) */QrMember qrMember = this.baseMapper.selectOne(new QueryWrapper<QrMember>().lambda().eq(QrMember::getId,memberId).select(QrMember::getId,QrMember::getNickName,QrMember::getParentId));
排序
orderByAsc/orderByDesc:
/**排序orderByAsc/orderByDesc* 查询所有员工信息按age正(降)序排, 如果age一样, 按id正(降)序排* SELECT id,name,password,email,age,admin,dept_id FROM employee ORDER BY age ASC,id ASC* SELECT id,name,password,email,age,admin,dept_id FROM employee ORDER BY age DESC,id DESC*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
//wrapper.orderByAsc("age","id");
wrapper.orderByDesc("age","id");
List<Employee> employees = employeeMapper.selectList(wrapper);
orderBy:
/**排序orderBy* 查询所有员工信息按age正序排, 如果age一样, 按id正序排* SELECT id,name,password,email,age,admin,dept_id FROM employee ORDER BY age ASC,id ASC*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
//参数一 排序开关,true表示执行排序,false反之 参数二 是否正序排 参数三 要进行排序的列
wrapper.orderBy(true,false,"age","id");
List<Employee> employees = employeeMapper.selectList(wrapper);
分组查询
groupBy:
/**分组查询groupBy* 以部门id进行分组查询,查每个部门员工个数* 由于返回的列名无法通过对象封装,因此只能用selectMaps* SELECT dept_id,count(id) count FROM employee GROUP BY dept_id*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.groupBy("dept_id");
wrapper.select("dept_id","count(id) count");
List<Map<String, Object>> maps = employeeMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
having:
/**分组查询having* 以部门id进行分组查询,查每个部门员工个数, 将大于3人的部门过滤出来* SELECT dept_id,count(id) count FROM employee GROUP BY dept_id HAVING count > 3*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.groupBy("dept_id").select("dept_id","count(id) count").having("count > 3");
List<Map<String, Object>> maps = employeeMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
条件查询
等于、不等于
/**条件查询:不等于* 查询name != hkj员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name <> ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.ne("name","hkj");
List<Employee> employees = employeeMapper.selectList(wrapper);
比较运算符gt、ge、lt、le
/**条件查询:比较运算符gt、ge、lt、le
* 查询age 大于18岁员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age > ?)
*/
ueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.gt("age",18);
List<Employee> employees = employeeMapper.selectList(wrapper);
between/notBetween:包含临界值
/**条件查询:between/notBetween:包含临界值* 查询年龄小于18或者大于30岁的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (age NOT BETWEEN ? AND ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notBetween("age",18,30);
List<Employee> employees = employeeMapper.selectList(wrapper);
isNull/isNotNull
/**条件查询:isNull/isNotNull* 查询admin为null 员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (admin IS NULL)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.isNull("admin");
List<Employee> employees = employeeMapper.selectList(wrapper);
in/notIn/inSql/notInSql
/**条件查询:in/notIn/inSql/notInSql* 查询id为3, 6 的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id IN (?,?))* 查询id不为3, 6 的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (id NOT IN (3,6))*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.in("id",3L,6L);
List<Employee> employees = employeeMapper.selectList(wrapper);
----------------------------------------------------------------
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.notInSql("id","3,6");
List<Employee> employees = employeeMapper.selectList(wrapper);
模糊查询
/**条件查询:模糊查询* 查询name中含有hkj字样的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ?)*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","hkj");
List<Employee> employees = employeeMapper.selectList(wrapper);
/**条件查询:模糊查询* 查询姓王的员工信息* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ?) 吴%*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.likeRight("name","吴");
List<Employee> employees = employeeMapper.selectList(wrapper);
employees.forEach(System.out::println);
逻辑运算符
/**条件查询:逻辑运算符* 查询name含有yoona字样的,或者 年龄在18到30之间的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? OR (age BETWEEN ? AND ?))*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","yoona").or(qw->qw.between("age",18,30)
);
List<Employee> employees = employeeMapper.selectList(wrapper);
/**条件查询:逻辑运算符* 查询name含有hkj字样的并且 年龄在小于18或者大于30的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? AND (age < ? OR age > ?))*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","hkj").and(qw->qw.lt("age",18).or().gt("age",30)
);
List<Employee> employees = employeeMapper.selectList(wrapper);
/**条件查询:逻辑运算符* 查询name含有hkj字样的并且 年龄在小于18或者大于30的员工* SELECT id,name,password,email,age,admin,dept_id FROM employee WHERE (name LIKE ? AND (age < ? OR age > ?))*/
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("name","hkj").and(qw->qw.lt("age",18).or().gt("age",30)
);
List<Employee> employees = employeeMapper.selectList(wrapper);
QueryWrapper<Employee> wrapper = new QueryWrapper<>();wrapper.like("name","hkj").and(qw->qw.notBetween("age",18,30));employeeMapper.selectList(wrapper);
map映射转换
/*** 将一个集合对象中的所有id提取出来映射并存入集合中*/List<QrMember> teamByMId = qrMemberService.getTeamByMId(qrMaterialGroupDTO.getLoginId());List<String> ids = teamByMId.stream().map(QrMember::getId).collect(Collectors.toList()));
通用Service接口
- 创建自定义service接口,继承IService接口
/*** mybatis-plus自定义服务接口* 1>自定义接口IEmployeeService 继承IService接口* 2>明确指定泛型,当前接口操作实体对象:Employee*/
public interface IEmployeeService extends IService<Employee> {}
- 创建service实现类,继承ServiceImpl<实体对象对应mapper接口,实体类对象>,并且实现自定义接口
/*** mybatis-plus服务层接口实现类:* 2>在ServiceImpl<M,T>上明确指定2个泛型:* 1:当前操作实体对象对应mapper接口EmployeeMapper* 2:当前操作实体类对象Employee*/
@Service
public class EmployeeService extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService{}
使用mybatis-plus实现分页操作
编写封装分页数据实体类
@Getter
@Setter
public class QueryObject {private int currentPage;private int pageSize;
}
@Getter
@Setter
public class EmployeeQuery extends QueryObject {private String keyword;
}
编写分页逻辑代码
//service
Page<Employee> query(EmployeeQuery qo);//serviceImpl
@Override
public IPage<Employee> query(EmployeeQuery qo) {IPage<Employee> page = new Page<>(qo.getCurrentPage(),qo.getPageSize());QueryWrapper<Employee> wrapper = new QueryWrapper<>();/*if (StringUtils.hasText(qo.getKeyword())) {wrapper.like("name", qo.getKeyword());}*/// 模糊查询 先判断keyword是否有值,有则 like该值wrapper.like(StringUtils.hasText(qo.getKeyword()), "name", qo.getKeyword()); //getBaseMapper().selectPage(page, wrapper); return super.page(page,wrapper);
}
分页测试
//controller
@Test
public void testQuery(){QueryObject qo = new QueryObject();qo.setCurrentPage(2);qo.setPageSize(3);IPage<Employee> page = employeeService.query(qo);System.out.println("当前页:" + page.getCurrent());System.out.println("总页数:" + page.getPages());System.out.println("每页显示条数:" + page.getSize());System.out.println("总记录数:" + page.getTotal());System.out.println("当前页显示记录:" + page.getRecords());
}
快速上手MyBatis-Plus相关推荐
- springboot 集成mybatis_SpringBoot快速集成Mybatis并轻松上手调试教程,请查收!
本篇主题:SpringBoot如何快速集成Mybatis并上手调试? 引入相关Jar依赖 这里使用Gradle作为构建工具,构建脚本build.gradle见下图: build.gradle 事实上, ...
- GORM CRUD 10 分钟快速上手
文章目录 1.ORM 是什么 2.GORM 是什么 3.安装 4.连接 DB 5.创建数据表 6.增加(Create) 7.查询(Read) 按照主键查询 IN 查询 AND 条件 OR 条件 Gro ...
- 一、快速上手SpringBoot
一.快速上手SpringBoot 一.快速上手SpringBoot 1.SpringBoot快速入门(一) 2.SpringBoot快速入门(二) 3.SpringBoot快速入门(三) 4.Spri ...
- Angular 初学者快速上手教程
课程介绍 本课程是一个系列基础教程,目标是带领读者上手实战,课程以新版本 Angular 的 3 个核心概念作为主线:组件.路由.模块,加上业务开发过程中必须用到的特性:工具.指令.表单.RxJS.i ...
- 【快速上手mac必备】常用优质mac软件推荐(音视频、办公、软件开发、辅助工具、系统管理、云存储)
本文章的主要内容是我作为一名大四学生.准程序员.up主这三种身份来给大家推荐一下 mac 上好用的软件以及工具.本人也是从去年9月份开始从windows阵营转移到了mac阵营,刚开始使用的时候,也曾主 ...
- 【转】Vue.js 2.0 快速上手精华梳理
Vue.js 2.0 快速上手精华梳理 Sandy 发掘代码技巧:公众号:daimajiqiao 自从Vue2.0发布后,Vue就成了前端领域的热门话题,github也突破了三万的star,那么对于新 ...
- 『转载』Debussy快速上手(Verdi相似)
『转载』Debussy快速上手(Verdi相似) Debussy 是NOVAS Software, Inc(思源科技)发展的HDL Debug & Analysis tool,这套软体主要不是 ...
- [转载]ESFramework 4.0 快速上手(15) -- 客户端登录验证
ESFramework 4.0 快速上手(15) -- 客户端登录验证 在之前版本的Rapid引擎中,是没有提供客户端登陆验证的机制的,如果要验证用户的帐号密码信息,我们只有自己手动通过自定义信息来实 ...
- WijmoJS 2019V1正式发布:全新的在线 Demo 系统,助您快速上手,开发无忧
2019独角兽企业重金招聘Python工程师标准>>> 下载WijmoJS 2019 v1 WijmoJS是为企业应用程序开发而推出的一系列包含HTML5和JavaScript的开发 ...
- react 快速上手开发_React中测试驱动开发的快速指南
react 快速上手开发 by Michał Baranowski 通过MichałBaranowski React中测试驱动开发的快速指南 (A quick guide to test-driven ...
最新文章
- 构建从目标到研发过程的全生命周期体验
- python读取excel-python 读取 Excel
- gc日志一般关注什么_GC日志说明
- ajax,php文件读取
- java接口常见问题分析_常见问题 - Apache ServiceComb
- SharePoint中CAML使用的一些总结
- 新手做2D手游该用哪些工具?
- ASP.NET MVC3 Action Filters详解(一)
- python容量变化类型有哪些_python基础数据类型补充以及编码的进阶
- php中表格怎么垂直居中,如何利用display:table-cell实现垂直居中?
- Unicode字符编码
- c#html表格样式大全,漂亮的表格样式(使用CSS样式表控制表格样式)
- btsync 文件同步工具 私有云盘
- 格子玻尔兹曼机(Lattice Boltzmann Method)系列5:LBM多相流实例之Shan-Chen模型
- 对象存储s3cmd使用手册
- python绘制小提琴图_matplotlib 小提琴图(violin plot)
- 【相机标定系列】相机sensor传感器尺寸,CMOS靶面尺寸,分辨​率​和​镜头​焦距,畸变处理效果,相机主点
- 参加项目管理培训的一些体会
- 初学JavaScript之猜测new操作符的原理
- vert.x中future的简单使用