@目录

什么是分页 ?

两个子模块功能的问题分析 和 解决方案

有条件查和无条件查询的影响 和 解决方案

项目案例: mysql + commons-dbutils+itcast-tools+BaseServlet + 分页+JSP+JSTL+EL+MVC模式


什么是分页?

如上所示,就是分页  ,不用多说了

子模块功能的问题分析 和 解决方案

@总功能分析  常规JDBC中,点击查询或输入条件查询,在页面中可显示查询出的所有记录,有多少记录就显示多少。在这种项目的基础上增加分页功能 。 @分页功能的宗旨 是无论什么样的查询,显示出的记录都是当前页的记录 。  所以,我们必须得向系统说明我们当前是要显示第几页的数据 。  自然,需要一个PageBean类

  1. public class PageBean<T> {
  2. private int pageCode ;//当前页码
  3. // private int totalPage ;//总页数,总页数应该由计算获取
  4. private int totalRecord;//总记录数
  5. private int pageSize;//每页记录数,这是参数是定做这个软件的甲方提出来的,在Servlet中直接定义为10了
  6. private List<T> beanList;//当前页的记录集合,方便整页记录的转移
  7. private String url ;//Url后的条件,条件查询设置的

这个PageBean类中封装了当前页、总记录数、当前页所有记录的集合等,系统通过当前页码这个参数返回pageSize条记录放在beanList集合中返回显示。

@子模块功能1 中首页的pageCode是1,尾页的pageCode是totalPage,上一页和下一页分别是pageCode-1 和pageCode+1 。

@子模块功能2 先来分析一个功能 : 当前页在页码列表中是第几个位置 ?

从上述两张图片中,点击1页码,当前页处于列表的第1个位置,点击2页码,当前页处于列表的第2个位置,..........,点击6页码,当前页处于列表的第6个位置,但是当点击7页码时,当前页还是处于列表的第6个位置 。 也就是说,假如每次一行只能显示10个页码,1~6页码的当前页的位置还是1~6,列表从页码1~页码10。   但是7~10页码的当前页的位置始终位于页码列表的第6个位置 ,列表从【页码2~页码11】~【页码X~页码totalPage】。其实非常好解决  ,列表头尾的判定 还是利用pageCode , begin = pageCode - 5   ,  end = pageCode + 4  。

@解决

  • 如果  totalPage  <=  10(列表长度),那么  begin  =  1,end  =  totalPage ;
  • 使用公式计算;begin  =  pc-5    ,    end  =   pc   +   4;
  • 头溢出:当  begin  <  1  时   ,   让  begin  =  1 ;
  • 尾溢出:当   end  >  totalPage  时   ,   让  end  =  totalPage   

有条件查和无条件查询的影响 和 解决方案

@产生一个问题  分页使得有条件查询产生一个严重问题 , 通过条件查询出40条记录,分4页显示,只有第一页是该条件下的记录,其余3页都是不带条件的记录 。所以我们必须告诉系统我们的条件是什么,每一页都要带着条件去查询和返回  。

@解决 在pageBean中设置url参数 , 这个参数将会携带这条件传递到Servlet中 。

项目案例(mvc+jdbc+c3p0+BaseServlet+mysql+JSP+EL+JSTL)

@使用   mysql数据库,c3p0数据库连接池,

采用commons-dbutils组件,封装好的JdbcUtils工具类和TxQueryRunner工具类辅助JDBC ,  (学习地址 : http://www.cnblogs.com/zyuqiang/p/7218083.html

BaseServlet辅助类

JSP+EL+JSTL

@数据库

  1. CREATE TABLE t_customer (
  2. username VARCHAR(50) DEFAULT NULL,
  3. age INT(11) DEFAULT NULL,
  4. balance DOUBLE(20,5) DEFAULT NULL
  5. );

t_customer

@源码

  1. package cn.kmust.pagination.customer.domain;
  2. /**
  3. * 实体类
  4. * 变量名字与数据库中对应字段名一样,便于封装操作
  5. * @author ZHAOYUQIANG
  6. *
  7. */
  8. public class Customer {
  9. private String username ; //用户
  10. private int age ; //年龄
  11. private double balance ; //资金
  12. public String getUsername() {
  13. return username;
  14. }
  15. public void setUsername(String username) {
  16. this.username = username;
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public double getBalance() {
  25. return balance;
  26. }
  27. public void setBalance(double balance) {
  28. this.balance = balance;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Customer [username=" + username + ", age=" + age + ", balance="
  33. + balance + "]";
  34. }
  35. public Customer(String username, int age, double balance) {
  36. super();
  37. this.username = username;
  38. this.age = age;
  39. this.balance = balance;
  40. }
  41. public Customer() {
  42. super();
  43. // TODO Auto-generated constructor stub
  44. }
  45.  
  46. }

Customer

  1. package cn.kmust.pagination.pageBean.domain;
  2. import java.util.List;
  3. import java.util.List;
  4. /**
  5. * 分页Bean
  6. * 把每一页中的当前页码、总页数、总记录数、每页记录数、当前页的记录集合等参数
  7. * 封装到该类的一个对象中,形成PageBean对象
  8. * @author ZHAOYUQIANG
  9. *
  10. */
  11. public class PageBean<T> {
  12. private int pageCode ;//当前页码
  13. // private int totalPage ;//总页数,总页数应该由计算获取
  14. private int totalRecord;//总记录数
  15. private int pageSize;//每页记录数,这是参数是定做这个软件的甲方提出来的,在Servlet中直接定义为10了
  16. private List<T> beanList;//当前页的记录集合,方便整页记录的转移
  17. private String url ;//Url后的条件,条件查询设置的
  18.  
  19. public String getUrl() {
  20. return url;
  21. }
  22. public void setUrl(String url) {
  23. this.url = url;
  24. }
  25. public int getPageCode() {
  26. return pageCode;
  27. }
  28. public void setPageCode(int pageCode) {
  29. this.pageCode = pageCode;
  30. }
  31. /*
  32. * 计算总页数,这个页数是由总记录和每页记录数决定的
  33. */
  34. public int getTotalPage() {
  35. int totalPage = totalRecord/pageSize ;
  36. return totalRecord%pageSize==0 ? totalPage : totalPage+1;
  37. }
  38. public int getTotalRecord() {
  39. return totalRecord;
  40. }
  41. public void setTotalRecord(int totalRecord) {
  42. this.totalRecord = totalRecord;
  43. }
  44. public int getPageSize() {
  45. return pageSize;
  46. }
  47. public void setPageSize(int pageSize) {
  48. this.pageSize = pageSize;
  49. }
  50. public List<T> getBeanList() {
  51. return beanList;
  52. }
  53. public void setBeanList(List<T> beanList) {
  54. this.beanList = beanList;
  55. }
  56.  
  57. }

PageBean

  1. package cn.kmust.pagination.customer.servlet;
  2.  
  3. import java.io.IOException;
  4. import java.io.UnsupportedEncodingException;
  5.  
  6. import javax.servlet.ServletException;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9.  
  10. import cn.itcast.commons.CommonUtils;
  11. import cn.itcast.servlet.BaseServlet;
  12. import cn.kmust.pagination.customer.domain.Customer;
  13. import cn.kmust.pagination.customer.service.CustomerService;
  14. import cn.kmust.pagination.pageBean.domain.PageBean;
  15. /**
  16. * Web层
  17. * 继承了我们自己写的BaseServlet类
  18. * 要求写的方法得与service()相同,
  19. * 并且.jsp页面必须传递过来一个method参数,如(add、deleter等)
  20. *
  21. * @author ZHAOYUQIANG
  22. *
  23. */
  24. public class CustomerServlet extends BaseServlet {
  25. /*
  26. * 依赖CustomerService
  27. */
  28. private CustomerService cstmService = new CustomerService();
  29. /**
  30. * 客户查询所有
  31. * 加入了分页功能 : 向页面返回当前页的所有记录, 返回的是一个对象,对象中封装了一个beanList集合
  32. * 该集合中存放这当前页所有记录
  33. * @param request
  34. * @param response
  35. * @return
  36. * @throws ServletException
  37. * @throws IOException
  38. */
  39. public String queryAll(HttpServletRequest request, HttpServletResponse response)
  40. throws ServletException, IOException {
  41. /*
  42. * 1. 获取list.jsp页面传递的pc
  43. * 2. 给定每页记录数ps = 10 。开发者根据客户的需求,认为规定的
  44. * 3. 使用pc和ps调用sevice方法,得到当前页的PageBean对象(该对象中封装了
  45. * 当前页的所有记录的集合等)
  46. * 4. 把PageBean保存到request域中
  47. * 5. 转发到list.jsp
  48. *
  49. */
  50. int pageCode = getCurrentPage(request);
  51. int pageSize = 10 ; //每页10记录
  52. PageBean<Customer> pageBean = cstmService.queryAll(pageCode,pageSize);
  53. /*
  54. * 因为与条件查询共用一个list.jsp,所以也需要加url
  55. */
  56. pageBean.setUrl(getUrl(request));
  57. request.setAttribute("pageBean", pageBean);
  58. return "f:/list.jsp";
  59.  
  60. }
  61.  
  62. /**
  63. * 条件查询
  64. * 具有分页功能,按照条件查询,条件也会被带入分页中
  65. * @param request
  66. * @param response
  67. * @return
  68. * @throws ServletException
  69. * @throws IOException
  70. */
  71. public String query(HttpServletRequest request, HttpServletResponse response)
  72. throws ServletException, IOException {
  73. /*
  74. * 1. 封装表单数据到Customer对象中
  75. * 只有一个属性username,是查询的条件critaria
  76. * 2. 得到当前页码 pageCode
  77. * 3. 给定pageSize 10
  78. * 4. 使用pageCode和pageSize以及条件对象,调用service方法得到query,
  79. * 返回当前页的PageBean对象,内封装了当前页的所有记录集合
  80. * 5. 把PageBean保存到request域中
  81. * 6. 转发到list.jsp显示成功信息
  82. */
  83. Customer criteria = CommonUtils.toBean(request.getParameterMap(), Customer.class);
  84. /*
  85. * 处理GET请求方式编码问题
  86. * 因为query.jsp表单使用的是get提交方法
  87. */
  88. criteria = encoding(criteria);
  89.  
  90. int pageCode = getCurrentPage(request);
  91. int pageSize = 10 ; //每页10记录
  92. PageBean<Customer> pageBean = cstmService.query(criteria,pageCode,pageSize);
  93. /*
  94. * 得到url,保存到pageBean对象中
  95. */
  96. pageBean.setUrl(getUrl(request));
  97. request.setAttribute("pageBean", pageBean);
  98. return "f:/list.jsp";
  99. }
  100.  
  101. /**
  102. * 处理GET请求乱码
  103. * 因为BaseSevlet类中只有处理POST请求的乱码,没有GET请求的乱码处理
  104. * @param criteria
  105. * @return
  106. * @throws UnsupportedEncodingException
  107. */
  108. private Customer encoding(Customer criteria) throws UnsupportedEncodingException {
  109. String username = criteria.getUsername();
  110.  
  111. if(username != null && !username.trim().isEmpty()){
  112. username = new String(username.getBytes("ISO-8859-1"),"utf-8");
  113. criteria.setUsername(username);
  114. }
  115. return criteria;
  116. }
  117.  
  118. /**
  119. * 获取pageCode(当前页码)
  120. * 传递到Servlet中的参数都是String类型的,所以需要转换
  121. * pageCode参数如果不存在,说明是第一次调用,当前页码默认为第一页
  122. * @param request
  123. * @return
  124. */
  125. private int getCurrentPage(HttpServletRequest request){
  126. String value = request.getParameter("pageCode");
  127. if(value == null || value.trim().isEmpty()){
  128. return 1 ;
  129. }
  130. return Integer.parseInt(value);
  131. }
  132.  
  133. /**
  134. * 截取url
  135. * 条件查询中需要使用
  136. * /项目名/Servlet路径?参数字符串
  137. * @param request
  138. * @return
  139. */
  140. private String getUrl(HttpServletRequest request){
  141. /*
  142. * 1. 获取项目名
  143. * 2. 获取Servlet路径
  144. * 3. 获取参数列表
  145. * 这个参数是条件
  146. */
  147. String contextPath = request.getContextPath();
  148. String servletPath = request.getServletPath();
  149. String queryString = request.getQueryString();
  150. /*
  151. * 4. 判断是否包含pageCode参数
  152. * 如果包含需要剪掉,不要这个参数
  153. */
  154. if(queryString.contains("&pageCode")){
  155. int index = queryString.lastIndexOf("&pageCode");
  156. queryString = queryString.substring(0,index);
  157. }
  158. return contextPath+servletPath+"?"+queryString ;
  159. }
  160.  
  161. }

CustomerServlet

  1. package cn.kmust.pagination.customer.service;
  2.  
  3. import java.sql.SQLException;
  4. import java.util.List;
  5.  
  6. import cn.itcast.jdbc.JdbcUtils;
  7. import cn.kmust.pagination.customer.dao.CustomerDao;
  8. import cn.kmust.pagination.customer.domain.Customer;
  9. import cn.kmust.pagination.pageBean.domain.PageBean;
  10.  
  11. /**
  12. * service 层 处理业务
  13. * @功能
  14. * 1. 条件查询
  15. * 2. 查询 所有用户
  16. * 3. 查询 所有记录行数
  17. * @author ZHAOYUQIANG
  18. *
  19. */
  20. public class CustomerService {
  21. /*
  22. * 依赖CustomerDao
  23. */
  24. CustomerDao cstmDao = new CustomerDao();
  25. /**
  26. * 条件查询
  27. *
  28. * @param criteria
  29. * @param pageCode
  30. * @param pageSize
  31. * @return
  32. */
  33. public PageBean<Customer> query(Customer criteria,int pc,int ps) {
  34. return cstmDao.query(criteria,pc,ps);
  35. }
  36. /**
  37. * 查询所有客户业务
  38. * 具有分页功能 : 返回PageBean对象 ,对象中封装了 当前页所有记录的集合
  39. * @param pc
  40. * @param ps
  41. * @return
  42. */
  43. public PageBean<Customer> queryAll(int pc,int ps){
  44. return cstmDao.queryAll(pc,ps);
  45. }
  46.  
  47. }

CustomerService

  1. package cn.kmust.pagination.customer.dao;
  2.  
  3. import java.sql.ResultSet;
  4. import java.sql.SQLException;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. import java.util.Map;
  8.  
  9. import javax.sql.DataSource;
  10.  
  11. import org.apache.commons.dbutils.QueryRunner;
  12. import org.apache.commons.dbutils.ResultSetHandler;
  13. import org.apache.commons.dbutils.handlers.BeanHandler;
  14. import org.apache.commons.dbutils.handlers.BeanListHandler;
  15. import org.apache.commons.dbutils.handlers.MapHandler;
  16. import org.apache.commons.dbutils.handlers.MapListHandler;
  17. import org.apache.commons.dbutils.handlers.ScalarHandler;
  18.  
  19. import cn.itcast.jdbc.JdbcUtils;
  20. import cn.itcast.jdbc.TxQueryRunner;
  21. import cn.kmust.pagination.customer.domain.Customer;
  22. import cn.kmust.pagination.pageBean.domain.PageBean;
  23.  
  24. /**
  25. *dao层
  26. * 对数据库的操作
  27. * @author ZHAOYUQIANG
  28. *
  29. */
  30. public class CustomerDao {
  31. private QueryRunner qr = new TxQueryRunner();
  32. /**
  33. * 对数据库进行查询所有客户操作
  34. * 具有分页功能 : 返回PageBean对象,该对象封装了当前页的所有记录的集合
  35. * 当前页的所有记录都放到beanList集合中,然后随当前页码等参数封装到pageBean中返回
  36. * @return
  37. */
  38. public PageBean<Customer> queryAll(int pc,int ps){
  39. try {
  40. /*
  41. * 有关数据库的操作:
  42. * 准备sql模版
  43. * 调用QueryRunner的query方法
  44. */
  45. /*该方法的任务:
  46. * 1. 创建PageBean对象
  47. */
  48. PageBean<Customer> pageBean = new PageBean<Customer>();
  49. /*
  50. * 2. 设置pc和ps,封装到我pageBean对象
  51. */
  52. pageBean.setPageCode(pc);
  53. pageBean.setPageSize(ps);
  54. /*
  55. * 3. 查询数据库得到totalRecord(数据库所有记录),封装到我pageBean对象
  56. */
  57. String sql = "select count(*) from t_customer";
  58. Number num = (Number)qr.query(sql,new ScalarHandler() );
  59. int totalRecord = num.intValue();
  60. pageBean.setTotalRecord(totalRecord);
  61. /*
  62. * 4. 查询数据库得到BeanList(当前页记录的集合),封装到我pageBean对象
  63. * 当前页到底是第几页,当前页有多少条记录呢?
  64. * 利用mysql的limit子句, (limit 4,10的意思是从第五行记录开始(包含第五行),查询10行记录)
  65. * 很明显当前页的是从第(pc-1)*ps行开始,查询ps行记录。
  66. * 根据limit子句的特点,巧妙的设计查询当前页的数据
  67. * 用order by 通过客户姓名来排序显示
  68. */
  69. sql = "select * from t_customer order by username limit ?,?";
  70. List<Customer> beanList = qr.query(sql,
  71. new BeanListHandler<Customer>(Customer.class),(pc-1)*ps,ps);
  72. pageBean.setBeanList(beanList);
  73. /*
  74. * 5. 返回PageBean对象
  75. */
  76. return pageBean ;
  77. } catch (SQLException e) {
  78. throw new RuntimeException(e);
  79. }
  80. }
  81. /**
  82. * 条件查询
  83. * 具有分页功能
  84. * @param criteria
  85. * @param pc
  86. * @param ps
  87. * @return
  88. */
  89. public PageBean<Customer> query(Customer criteria,int pc,int ps) {
  90. try {
  91. /*
  92. * 1. 创建PageBean对象
  93. * 2. 设置已有属性,pc和ps(pageCode和pageSize)
  94. * 3. 通过条件查询数据库得到totalRecord
  95. * 4. 查询数据库,返回beanList(当前页记录的集合)
  96. */
  97. PageBean<Customer> pageBean = new PageBean<Customer>();
  98. pageBean.setPageCode(pc);
  99. pageBean.setPageSize(ps);
  100. /*
  101. * 3. 通过条件查询数据库得到totalRecord
  102. */
  103. String sql1 = null;
  104. String username = criteria.getUsername();
  105. if(username != null && !username.trim().isEmpty()){
  106. sql1 = "select count(*) from t_customer where username like ?" ;
  107. }
  108. Object[] params1 = {"%"+username+"%"};
  109. /*
  110. * 3.3. 得到totalRecord
  111. */
  112. Number num = (Number)qr.query(sql1,
  113. new ScalarHandler(),params1);
  114. int totalRecord = num.intValue();
  115. pageBean.setTotalRecord(totalRecord);
  116. /*
  117. * 4. 查询数据库,返回beanList(当前页记录的集合)
  118. * 还是需要拼凑sql语句,并且需要limit子句
  119. * params中需要给出limit后两个问号对应的值
  120. *
  121. */
  122.  
  123. String sql2 = "select * from t_customer where username like ? limit ?,?";
  124.  
  125. Object[] params = {"%"+username+"%",(pc-1)*ps,ps};
  126. List<Customer> beanList = qr.query(sql2,
  127. new BeanListHandler<Customer>(Customer.class),
  128. params);
  129. pageBean.setBeanList(beanList);
  130. return pageBean ;
  131. } catch (SQLException e) {
  132. throw new RuntimeException(e);
  133. }
  134.  
  135. }
  136. }

CustomerDao

@项目download   http://files.cnblogs.com/files/zyuqiang/jdbcStudy_Demo5_pagination.rar

分页功能的实现——Jdbc && JSP的更多相关文章

  1. JDBC使用数据库来完成分页功能

    本篇讲诉如何在页面中通过操作数据库来完成数据显示的分页功能.当一个操作数据库进行查询的语句返回的结果集内容如果过多,那么内存极有可能溢出,所以在大数据的情况下分页是必须的.当然分页能通过很多种方式来实 ...

  2. jsp、js分页功能的简单总结

    一.概述 首先,我们要明确为何需要分页技术,主要原因有以下: 1.分页可以提高客户体验度,适当地选择合适的数据条数,让页面显得更有条理,使得用户体验感良好,避免过多数据的冗余. 2.提高性能的需要.分 ...

  3. 基于SSM框架的简易的分页功能——包含maven项目的搭建

    新人第一次发帖,有什么不对的地方请多多指教~~ 分页这个功能经常会被使用到,我之前学习的时候找了很多资源,可都看不懂(笨死算了),最后还是在朋友帮助下做出了这个分页.我现在把我所能想到的知识 做了一个 ...

  4. 《JavaWeb从入门到改行》分页功能的实现

    @目录 什么是分页 ? 两个子模块功能的问题分析 和 解决方案 有条件查和无条件查询的影响 和 解决方案 项目案例: mysql + commons-dbutils+itcast-tools+Base ...

  5. 【jQuery 分页】jQuery分页功能的实现

    自写的jQuery实现分页功能的分页组件: 功能效果如下: 分页组件就是上图中的三部分, 分别放在表格上部  和下部 . 其中, 1>>>页面的代码如下: product.jsp 其 ...

  6. spring和mybatis集成,自动生成model、mapper,增加mybatis分页功能

    软件简介 Spring是一个流行的控制反转(IoC)和面向切面(AOP)的容器框架,在java webapp开发中使用广泛.http://projects.spring.io/spring-frame ...

  7. aspnetpager+repeater+oracle实现分页功能

    一.设计原理阐述 数据查询分页,这个功能相信大家都很熟悉,通过数据库或其它数据源进行查询操作后,将获得的数据显示到界面上,但是由于数据量太大,不能一次性完全的显示出来,就有了数据分页的需求.这个需求在 ...

  8. MyBatis 拦截器 (实现分页功能)

    由于业务关系 巴拉巴拉巴拉 好吧 简单来说就是 原来的业务是 需要再实现类里写 selectCount 和selectPage两个方法才能实现分页功能 现在想要达到效果是 只通过一个方法就可以实现 也 ...

  9. hibernate和struts2实现分页功能

    1.DAO层接口的设计,定义一个PersonDAO接口,里面声明了两个方法: public interface PersonDAO { public List<Person> queryB ...

随机推荐

  1. Unexpected end of input 和 Unexpected token var 和 Unexpected token ;

    在写jsp的时候使用的一段代码一直调试,出现Unexpected token ; 错误. 所以最后把代码各种精简,得到了如下的测试示例代码 <% String aaa="123&quo ...

  2. python爬虫 模拟登陆校园网-初级

    最近跟同学学习爬虫的时候看到网上有个帖子,好像是山大校园网不稳定,用py做了个模拟登陆很有趣,于是我走上了一条不归路..... 先上一张校园网截图 首先弄清一下模拟登陆的原理: 1:服务器判定浏览器登 ...

  3. nginx之 nginx-1.9.7 + tomcat-8.5.15 反向代理+应用负载均衡 安装配置

    环境说明:nginx 反向代理服务器 ip 为: 10.219.24.26tomcat1 应用服务器 ip 为: 10.219.24.21tomcat3 应用服务器 ip 为: 10.219.24.2 ...

  4. SQL之删除触发器

    比如要删除的触发器名字叫dbo.test_trigger. 先判断这个触发器是否存在,判断存在后删除 if exists (select * from sysobjects where name = ...

  5. java 类变量的初始化

    有代码如下:class Price{    final static Price INSTANCE = NEW Price(2.8);    static double initPrice = 20; ...

  6. VR虚拟现实技术在教育领域的前景展望

    VR虚拟现实技术在教育领域的前景展望 VR虚拟现实技术能迅速火起来,是基于它突破了人们对三维空间在时间与地域上的感知限制,以及市场需求愿景的升级.此技术可广泛地应用到城市规划.室内设计.工业仿真.古迹 ...

  7. java中方法总结(每周更新)

    1.URLEncoder.encode(username,"utf-8")将"utf-8"编码的username先解码,然后再采用URL编码 2.URLDeco ...

  8. PHP基础入门(四)---PHP数组实用基础知识

    PHP数组 数组是特殊的变量,它可以同时保存一个以上的值. ***关键词:数组基础.数组遍历.超全局数组.数组功能.数组函数. 下面来和大家分享一下有关PHP的数组基础知识,希望对你PHP的学习有所帮 ...

  9. Linux下Shadow socks的安装和配置

    实在受不了在Windows下编程,所以自己就安装了一个Ubutun,公司用的FQ软件shadowsocks在Windows上用起来很简单很爽,但是在Ubutun上的安装和配置就没那么简单了,写下这篇文 ...

  10. 浅谈WEB编辑器——HBuilder

    我自己用过的WEB编辑器有两种:HBuilder和Dreamweaver.这两种编辑器各有各的特点,但是相对来说,我倾向于前者:后者给我的感觉就是功能繁杂,运行起来慢,而且编码的便捷度不高,时不时需要 ...