1.总体架构

MVC 设计模式:
Model:POJO(Plain Old Java Object)
Controller:Servlet
View:JSP + EL + JSTL

2.技术选型

数据库:MySQL
数据源:C3P0
JDBC 工具:DBUtils
事务解决方案:Filter + ThreadLocal
Ajax 解决方案:jQuery + JavaScript + JSON + google-gson
层之间解耦方案:工厂设计模式

3.数据表设计

相关表的创建

  1. DROP TABLE IF EXISTS `account`;
  2.  
  3. CREATE TABLE `account` (
  4. `accountid` INT(11) NOT NULL AUTO_INCREMENT,
  5. `balance` FLOAT DEFAULT NULL,
  6. PRIMARY KEY (`accountid`)
  7. )
  8. INSERT INTO `account`(`accountid`,`balance`) VALUES (1,9740);
  9.  
  10. DROP TABLE IF EXISTS `mybooks`;
  11. CREATE TABLE `mybooks` (
  12. `Id` INT(11) NOT NULL AUTO_INCREMENT,
  13. `Author` VARCHAR(30) NOT NULL,
  14. `Title` VARCHAR(30) NOT NULL,
  15. `Price` FLOAT NOT NULL,
  16. `Publishingdate` DATE NOT NULL,
  17. `Salesamount` INT(11) NOT NULL,
  18. `Storenumber` INT(11) NOT NULL,
  19. `Remark` TEXT NOT NULL,
  20. PRIMARY KEY (`Id`)
  21. )
  22. INSERT INTO `mybooks`(`Id`,`Author`,`Title`,`Price`,`Publishingdate`,`Salesamount`,`Storenumber`,`Remark`)
  23. VALUES (1,'Tom','Java 编程思想',50,'2009-06-22',17,83,'Good Java Book'),
  24. (2,'Jerry','Oracle DBA 教材',60,'2009-06-22',12,88,'Good Oracle Book'),
  25. (3,'Bob','Ruby',50,'2009-06-22',12,88,'Good 0'),
  26. (4,'Mike','Javascript',51,'2009-06-22',0,100,'Good 1'),
  27. (5,'Rose','Ajax',52,'2009-06-22',0,100,'Good 2'),
  28. (6,'Backham','Struts',53,'2009-06-22',0,100,'Good 3'),
  29. (7,'Zidon','Hibernate',54,'2009-06-22',2,12,'Good 4'),
  30. (8,'Ronaerdo','Spring',55,'2009-06-22',2,13,'Good 5'),
  31. (9,'Clinsman','Cvs',56,'2009-06-22',0,16,'Good 6'),
  32. (10,'Kaka','Seo',57,'2009-06-22',0,17,'Good 7'),
  33. (11,'Lauer','Lucence',58,'2009-06-22',0,18,'Good 8'),
  34. (12,'Kasi','Guice',59,'2009-06-22',0,19,'Good 9'),
  35. (13,'Prierlo','Mysql',60,'2009-06-22',6,14,'Good 10'),
  36. (14,'Haohaidong','DB2',61,'2009-06-22',9,12,'Good 11'),
  37. (15,'Feige','Sybase',62,'2009-06-22',8,14,'Good 12'),
  38. (16,'Tuoleisi','DBDesign',63,'2009-06-22',0,23,'Good 13'),
  39. (17,'Jielade','Eclipse',64,'2009-06-22',0,24,'Good 14'),
  40. (18,'Teli','Netbeans',65,'2009-06-22',0,25,'Good 15'),
  41. (19,'Lapade','C#',66,'2009-06-22',0,26,'Good 16'),
  42. (20,'Runi','JDBC',67,'2009-06-22',0,27,'Good 17'),
  43. (21,'JoeKeer','Php',68,'2009-06-22',0,28,'Good 18'),
  44. (22,'Jordan','MysqlFront',69,'2009-06-22',5,24,'Good 19'),
  45. (23,'Yaoming','NoteBook',70,'2009-06-22',5,25,'Good 20'),
  46. (24,'Yi','C',71,'2009-06-22',5,26,'Good 21'),
  47. (25,'Sun','Css',72,'2009-06-22',0,32,'Good 22'),
  48. (26,'Xuliang','JQuery',73,'2009-06-22',0,33,'Good 23'),
  49. (27,'Meixi','Ext',74,'2009-06-22',0,34,'Good 24'),
  50. (28,'Apple','iphone',75,'2009-06-22',0,35,'Good 25'),
  51. (29,'Aigo','dc',76,'2009-06-22',0,36,'Good 26'),
  52. (30,'Sony','psp',77,'2009-06-22',0,100,'Good 27'),
  53. (31,'IRiver','mp3',78,'2009-06-22',0,100,'Good 28'),
  54. (32,'Sansing','TV',79,'2009-06-22',0,100,'Good 29');
  55.  
  56. DROP TABLE IF EXISTS `trade`;
  57. CREATE TABLE `trade` (
  58. `tradeid` INT(11) NOT NULL AUTO_INCREMENT,
  59. `userid` INT(11) NOT NULL,
  60. `tradetime` DATETIME NOT NULL,
  61. PRIMARY KEY (`tradeid`),
  62. KEY `user_id_fk` (`userid`),
  63. CONSTRAINT `user_id_fk` FOREIGN KEY (`userid`) REFERENCES `userinfo` (`userid`)
  64. )
  65. INSERT INTO `trade`(`tradeid`,`userid`,`tradetime`) VALUES (12,1,'2012-11-01 00:00:00'),(13,1,'2012-11-01 00:00:00'),
  66. (14,1,'2012-11-01 00:00:00')
  67. ,(15,1,'2012-12-20 00:00:00'),
  68. (16,1,'2012-12-20 00:00:00');
  69.  
  70. DROP TABLE IF EXISTS `tradeitem`;
  71. CREATE TABLE `tradeitem` (
  72. `itemid` INT(11) NOT NULL AUTO_INCREMENT,
  73. `bookid` INT(11) DEFAULT NULL,
  74. `quantity` INT(11) DEFAULT NULL,
  75. `tradeid` INT(11) DEFAULT NULL,
  76. PRIMARY KEY (`itemid`),
  77. KEY `book_id_fk` (`bookid`),
  78. KEY `trade_id_fk` (`tradeid`),
  79. CONSTRAINT `book_id_fk` FOREIGN KEY (`bookid`) REFERENCES `mybooks` (`Id`),
  80. CONSTRAINT `trade_id_fk` FOREIGN KEY (`tradeid`) REFERENCES `trade` (`tradeid`)
  81. )
  82. INSERT INTO `tradeitem`(`itemid`,`bookid`,`quantity`,`tradeid`) VALUES (22,1,10,12),
  83. (23,2,10,12),(24,3,10,12),(25,1,1,13),(26,13,2,13),(27,14,3,13),(28,15,4,13),(29,1,1,14),
  84. (30,13,2,14),(31,14,3,14),(32,15,4,14),(33,22,5,14),(34,23,5,14),(35,24,5,14),(36,2,1,15),
  85. (37,1,2,15),(38,3,1,15),(39,2,1,16),(40,1,3,16),(41,3,1,16);
  86.  
  87. DROP TABLE IF EXISTS `userinfo`;
  88. CREATE TABLE `userinfo` (
  89. `userid` INT(11) NOT NULL AUTO_INCREMENT,
  90. `username` VARCHAR(50) DEFAULT NULL,
  91. `accountid` INT(11) DEFAULT NULL,
  92. PRIMARY KEY (`userid`),
  93. KEY `account_id_fk` (`accountid`),
  94. CONSTRAINT `account_id_fk` FOREIGN KEY (`accountid`) REFERENCES `account` (`accountid`)
  95. )
  96. INSERT INTO `userinfo`(`userid`,`username`,`accountid`) VALUES (1,'Tom',1),(2,'AAA',1),(3,'BB',1),(4,'CC',1),(5,'DD',1),(6,'EE',1);

4.搭建环境

加入 C3P0 数据源

--加入 jar 包
     --加入配置文件
     --编辑配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <c3p0-config>
  3.  
  4. <named-config name="javawebapp">
  5. <!--提供获取连接的四个基本信息 -->
  6. <!--连接本地主机的话: jbdc:mysql://localhost:3306/test 可写成jbdc:mysql:///test -->
  7. <property name="driverClass">com.mysql.jdbc.Driver</property>
  8. <property name="jdbcUrl">jdbc:mysql://localhost:3306/bookstore</property>
  9. <property name="user">root</property>
  10. <property name="password">123456</property>
  11.  
  12. <!-- 对数据库连接池管理的基本信息 -->
  13. <!-- 当数据库连接池中的连接数不够时,c3p0一次向数据库服务器申请的连接数 -->
  14. <property name="acquireIncrement">5</property>
  15. <!-- 初始化时的连接数 -->
  16. <property name="initialPoolSize">10</property>
  17. <!-- 维护的最少连接数 -->
  18. <property name="minPoolSize">10</property>
  19. <!-- 维护的最多的连接数 -->
  20. <property name="maxPoolSize">100</property>
  21. <!-- 最多维护的Satement的个数 -->
  22. <property name="maxStatements">50</property>
  23. <!-- 每个连接最多使用Statement的个数 -->
  24. <property name="maxStatementsPerConnection">2</property>
  25.  
  26. </named-config>
  27. </c3p0-config>

加入 dbutils 工具类
加入 JSTL
其它:使用随时加入

5.Dao 层设计

目录结构

Dao.java

  1. package com.aff.bookstore.dao;
  2.  
  3. import java.util.List;
  4.  
  5. /**
  6. * Dao 接口, 定义 Dao 的基本操作, 由 BaseDao 提供实现.
  7. * @param <T>: Dao 实际操作的泛型类型
  8. */
  9. public interface Dao<T> {
  10.  
  11. /**
  12. * 执行 INSERT 操作, 返回插入后的记录的 ID
  13. * @param sql: 待执行的 SQL 语句
  14. * @param args: 填充占位符的可变参数
  15. * @return: 插入新记录的 id
  16. */
  17. long insert(String sql, Object ... args);
  18.  
  19. /**
  20. * 执行 UPDATE 操作, 包括 INSERT(但没有返回值), UPDATE, DELETE
  21. * @param sql: 待执行的 SQL 语句
  22. * @param args: 填充占位符的可变参数
  23. */
  24. void update(String sql, Object ... args);
  25.  
  26. /**
  27. * 执行单条记录的查询操作, 返回与记录对应的类的一个对象
  28. * @param sql: 待执行的 SQL 语句
  29. * @param args: 填充占位符的可变参数
  30. * @return: 与记录对应的类的一个对象
  31. */
  32. T query(String sql, Object ... args);
  33.  
  34. /**
  35. * 执行多条记录的查询操作, 返回与记录对应的类的一个 List
  36. * @param sql: 待执行的 SQL 语句
  37. * @param args: 填充占位符的可变参数
  38. * @return: 与记录对应的类的一个 List
  39. */
  40. List<T> queryForList(String sql, Object ... args);
  41.  
  42. /**
  43. * 执行一个属性或值的查询操作, 例如查询某一条记录的一个字段, 或查询某个统计信息, 返回要查询的值
  44. * @param sql: 待执行的 SQL 语句
  45. * @param args: 填充占位符的可变参数
  46. * @return: 执行一个属性或值的查询操作, 例如查询某一条记录的一个字段, 或查询某个统计信息, 返回要查询的值
  47. */
  48. <V> V getSingleVal(String sql, Object ... args);
  49.  
  50. /**
  51. * 执行批量更新操作
  52. * @param sql: 待执行的 SQL 语句
  53. * @param args: 填充占位符的可变参数
  54. */
  55. void batch(String sql, Object[]... params);
  56. }

BookDAO.java

  1. package com.aff.bookstore.dao;
  2.  
  3. import java.util.Collection;
  4. import java.util.List;
  5.  
  6. import com.aff.bookstore.domain.Book;
  7. import com.aff.bookstore.domain.ShoppingCartItem;
  8. import com.aff.bookstore.web.CriteriaBook;
  9. import com.aff.bookstore.web.Page;
  10.  
  11. public interface BookDAO {
  12.  
  13. /**
  14. * 根据 id 获取指定 Book 对象
  15. * @param id
  16. * @return
  17. */
  18. public abstract Book getBook(int id);
  19.  
  20. /**
  21. * 根据传入的 CriteriaBook 对象返回对应的 Page 对象
  22. * @param cb
  23. * @return
  24. */
  25. public abstract Page<Book> getPage(CriteriaBook cb);
  26.  
  27. /**
  28. * 根据传入的 CriteriaBook 对象返回其对应的记录数
  29. * @param cb
  30. * @return
  31. */
  32. public abstract long getTotalBookNumber(CriteriaBook cb);
  33.  
  34. /**
  35. * 根据传入的 CriteriaBook 和 pageSize 返回当前页对应的 List
  36. * @param cb
  37. * @param pageNo
  38. * @param pageSize
  39. * @return
  40. */
  41. public abstract List<Book> getPageList(CriteriaBook cb,int pageSize);
  42.  
  43. /**
  44. * 返回指定 id 的 book 的 storeNumber 字段的值
  45. * @param id
  46. * @return
  47. */
  48. public abstract int getStoreNumber(Integer id);
  49.  
  50. /**
  51. * 根据传入的 ShoppingCartItem 的集合,
  52. * 批量更新 books 数据表的 storenumber 和 salesnumber 字段的值
  53. * @param items
  54. */
  55. public abstract void batchUpdateStoreNumberAndSalesAmount(
  56. Collection<ShoppingCartItem> items);
  57.  
  58. }

BaseDAO.java

  1. package com.aff.bookstore.dao.impl;
  2.  
  3. import java.sql.Connection;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.Statement;
  7. import java.util.List;
  8.  
  9. import org.apache.commons.dbutils.QueryRunner;
  10. import org.apache.commons.dbutils.handlers.BeanHandler;
  11. import org.apache.commons.dbutils.handlers.BeanListHandler;
  12. import org.apache.commons.dbutils.handlers.ScalarHandler;
  13.  
  14. import com.aff.bookstore.dao.Dao;
  15. import com.aff.bookstore.db.JDBCUtils;
  16. import com.aff.bookstore.utils.ReflectionUtils;
  17.  
  18. public class BaseDAO<T> implements Dao<T> {
  19. private QueryRunner queryRunner = new QueryRunner();
  20. private Class<T> clazz;
  21.  
  22. public BaseDAO() {
  23. clazz = ReflectionUtils.getSuperGenericType(getClass());
  24.  
  25. }
  26.  
  27. @Override
  28. public long insert(String sql, Object... args) {
  29. // 我们需要返回它的主键id值
  30. // update 中的insert 操作没有返回值
  31. // quertRunner也没有返回值
  32. // 此时需要使用原生的jdbc写
  33. long id = 0;
  34. Connection connection = null;
  35. PreparedStatement preparedStatement = null;
  36. ResultSet resultSet = null;
  37.  
  38. try {
  39. connection = JDBCUtils.getConnection();
  40. preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
  41.  
  42. if (args != null) {
  43. for (int i = 0; i < args.length; i++) {
  44. preparedStatement.setObject(i + 1, args[i]);
  45. }
  46. }
  47. preparedStatement.executeUpdate();
  48.  
  49. // 获取生成的主键值
  50. resultSet = preparedStatement.getGeneratedKeys();
  51. if (resultSet.next()) {
  52. id = resultSet.getLong(1);// 第一列主键值 id
  53. }
  54.  
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. } finally {
  58. JDBCUtils.release(resultSet, preparedStatement);
  59. JDBCUtils.release(connection);
  60. }
  61. return id;
  62. }
  63.  
  64. @Override
  65. public void update(String sql, Object... args) {
  66. Connection connection = null;
  67.  
  68. try {
  69. connection = JDBCUtils.getConnection();
  70. queryRunner.update(connection, sql,args);
  71.  
  72. } catch (Exception e) {
  73. e.printStackTrace();
  74. } finally {
  75. JDBCUtils.release(connection);
  76. }
  77. }
  78.  
  79. @Override
  80. public T query(String sql, Object... args) {
  81. Connection connection = null;
  82.  
  83. try {
  84. connection = JDBCUtils.getConnection();
  85. return queryRunner.query(connection, sql, new BeanHandler<>(clazz), args);
  86.  
  87. } catch (Exception e) {
  88. e.printStackTrace();
  89. } finally {
  90. JDBCUtils.release(connection);
  91. }
  92. return null;
  93. }
  94.  
  95. @Override
  96. public List<T> queryForList(String sql, Object... args) {
  97. Connection connection = null;
  98.  
  99. try {
  100. connection = JDBCUtils.getConnection();
  101. return queryRunner.query(connection, sql, new BeanListHandler<>(clazz), args);
  102.  
  103. } catch (Exception e) {
  104. e.printStackTrace();
  105. } finally {
  106. JDBCUtils.release(connection);
  107. }
  108. return null;
  109. }
  110.  
  111. @Override
  112. public <V> V getSingleVal(String sql, Object... args) {
  113. Connection connection = null;
  114.  
  115. try {
  116. connection = JDBCUtils.getConnection();
  117. return (V) queryRunner.query(connection, sql, new ScalarHandler(), args);
  118.  
  119. } catch (Exception e) {
  120. e.printStackTrace();
  121. } finally {
  122. JDBCUtils.release(connection);
  123. }
  124. return null;
  125. }
  126.  
  127. @Override
  128. public void batch(String sql, Object[]... params) {
  129. Connection connection = null;
  130.  
  131. try {
  132. connection = JDBCUtils.getConnection();
  133. queryRunner.batch(connection, sql, params);
  134. } catch (Exception e) {
  135. e.printStackTrace();
  136. } finally {
  137. JDBCUtils.release(connection);
  138. }
  139. }
  140. }

BookDaoImpl.java

  1. package com.aff.bookstore.dao.impl;
  2.  
  3. import java.util.Collection;
  4. import java.util.List;
  5.  
  6. import com.aff.bookstore.dao.BookDAO;
  7. import com.aff.bookstore.domain.Book;
  8. import com.aff.bookstore.domain.ShoppingCartItem;
  9. import com.aff.bookstore.web.CriteriaBook;
  10. import com.aff.bookstore.web.Page;
  11.  
  12. public class BookDaoImpl extends BaseDAO<Book> implements BookDAO {
  13.  
  14. @Override
  15. public Book getBook(int id) {
  16. String sql = "select id, author, title, price ,publishingDate,salesAmount,storeNumber,remark from mybooks where id = ? ";
  17. return query(sql, id);
  18. }
  19.  
  20. @Override
  21. public Page<Book> getPage(CriteriaBook cb) {
  22. Page page = new Page<>(cb.getPageNo());
  23. page.setTotalItemNumber(getTotalBookNumber(cb));
  24. // 检验 pageNo的合法性
  25. cb.setPageNo(page.getPageNo());
  26.  
  27. page.setList(getPageList(cb, 3));
  28. return page;
  29. }
  30.  
  31. // 获取在这个价格区间的有多少条数目
  32. @Override
  33. public long getTotalBookNumber(CriteriaBook cb) {
  34. String sql = "select count(id) from mybooks where price >=? and price <= ? ";
  35. return getSingleVal(sql, cb.getMinPrice(), cb.getMaxPrice());
  36. }
  37.  
  38. @Override
  39. public List<Book> getPageList(CriteriaBook cb, int pageSize) {
  40. // 起始从0 开始的,所以 (cb.getPageNo()- 1) *pageSize,pageSize
  41. String sql = "select id, author, title, price ,publishingDate,salesAmount,storeNumber,remark from mybooks where price >=? and price <= ? limit ?,?";
  42. return queryForList(sql, cb.getMinPrice(), cb.getMaxPrice(), (cb.getPageNo() - 1) * pageSize, pageSize);
  43. }
  44.  
  45. @Override
  46. public int getStoreNumber(Integer id) {
  47. String sql = "select storeNumber from mybooks where id = ?";
  48. return getSingleVal(sql, id);
  49. }
  50.  
  51. @Override
  52. public void batchUpdateStoreNumberAndSalesAmount(Collection<ShoppingCartItem> items) {
  53.  
  54. }
  55. }

(一)DAO设计及BaseDAO和BookDAO的实现的更多相关文章

  1. SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装

    SpringJdbc持久层封装,Spring jdbcTemplate封装,springJdbc泛型Dao,Spring baseDao封装 >>>>>>>& ...

  2. JPA的泛型DAO设计及使用

    使用如Hibernate或者JPA作为持久化的解决方案时,设计一个泛型的DAO抽象父类可以方便各个实体的通用CRUD操作.由于此时大部分实体DAO的CRUD操作基本一样,采用泛型设计解决这个问题,带来 ...

  3. Dao层抽取BaseDao公共方法

    设计IBseDao接口,定义公共的CRUD方法. // IBaseDao 接口,定义公共的CRUD方法 public interface IBaseDao<T> { public void ...

  4. 针对Student表的DAO设计实例

    完整代码以及junit,mysql--connector包下载地址 : https://github.com/CasterWx/MyStudentDao 表信息: 代码: dao包----impl包- ...

  5. Java秒杀简单设计二:数据库表和Dao层设计

    Java秒杀简单设计二:数据库表Dao层设计 上一篇中搭建springboot项目环境和设计数据库表  https://www.cnblogs.com/taiguyiba/p/9791431.html ...

  6. JDBC中DAO+service设计思想

    一.DAO设计思想 a) Data access Object(数据访问对象):前人总结出的一种固定模式的设计思想. 高可读性. 高复用性. 高扩展性. b) JDBC代码实现的增删改查操作是有复用需 ...

  7. OA项目笔记-从建立接口 dao impl action jsp等框架实现crud

    1,设计 BaseDao 与 BaseDaoImpl 1,设计接口 BaseDao 1,每个实体都应有一个对应的Dao接口,封装了对这个实体的数据库操作.例 实体 Dao接口 实现类 ======== ...

  8. Dao模型设计(基于Dao与Hebernate框架)

    以前没有Dao设计模型之前,一般都是这样的流程: ①先设计实体对象 学生对象: package com.itheima.domain; import java.io.Serializable; imp ...

  9. 从0开始学习ssh之basedao

    用于所有dao里边会有许多相同的方法,例如save,update等等.应此设计一个basedao,所有dao都继承它.这样可以省去许多工作量. basedao如下 package cn.itcast. ...

随机推荐

  1. Python编程求解第1天1分钱之后每天两倍持续一个月的等比数列问题

    一.问题 问题1 场景:如果你未来的丈母娘要求你,第1天给她1分钱,第2天给2分钱,第3天给4分钱,以此类推,每天给前一天的2倍,给1个月(按30天)算就行.问:第30天给多少钱,总共给多少钱? 问题 ...

  2. 「从零单排HBase 09」Hbase的那些数据结构和算法

    在之前学习MySQL的时候,我们知道存储引擎常用的索引结构有B+树索引和哈希索引. 而对HBase的学习,也离不开索引结构的学习,它使用了一种LSM树((Log-Structured Merge-Tr ...

  3. 给springboot增加XSS跨站脚本攻击防护功能

    XSS原理 xss攻击的原理是利用前后端校验不严格,用户将攻击代码植入到数据中提交到了后台,当这些数据在网页上被其他用户查看的时候触发攻击 举例:用户提交表单时把地址写成:山东省济南市<scri ...

  4. spring学习笔记(五)自定义spring-boot-starter(1)

    在我们开始定义之前我们应该知道springBoot的大致运行原理,我们从springBoot启动类开始.首先我们看下这个注解,@SpringBootApplication,跟进去可以看到如下代码: @ ...

  5. 微软关于LINQ的101个例子

    记录,备查. 101 LINQ Sqmples

  6. Mysql常用sql语句(14)- 多表查询

    测试必备的Mysql常用sql语句,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1683347.html 前言 ...

  7. 测试开发专题:如何在spring-boot中进行参数校验

    上文我们讨论了spring-boot如何去获取前端传递过来的参数,那传递过来总不能直接使用,需要对这些参数进行校验,符合程序的要求才会进行下一步的处理,所以本篇文章我们主要讨论spring-boot中 ...

  8. 「从零单排HBase 12」HBase二级索引Phoenix使用与最佳实践

    Phoenix是构建在HBase上的一个SQL层,能让我们用标准的JDBC APIs对HBase数据进行增删改查,构建二级索引.当然,开源产品嘛,自然需要注意“避坑”啦,阿丸会把使用方式和最佳实践都告 ...

  9. 「雕爷学编程」Arduino动手做(34)——三色LED交通灯模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  10. ios中fixed元素在滚动布局中的延时渲染问题

    在之前做的一个demo中,有个视图是内滚动的,里边有个bar用了fixed,不是fixed在最外层视图的顶部和底部,在微信/safari/chrome/其他浏览器app上都没出现问题. 然后今天,我把 ...