• 裸系统封装


    封装过程:

    1、建立一个web工程

      新建一个index.jsp;

     1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
     2 <%
     3 String path = request.getContextPath();
     4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
     5 %>
     6 
     7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     8 <html>
     9   <head>
    10     <base href="<%=basePath%>">
    11     
    12     <title>My JSP 'index.jsp' starting page</title>
    13     <meta http-equiv="pragma" content="no-cache">
    14     <meta http-equiv="cache-control" content="no-cache">
    15     <meta http-equiv="expires" content="0">    
    16     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    17     <meta http-equiv="description" content="This is my page">
    18     <!--
    19     <link rel="stylesheet" type="text/css" href="styles.css">
    20     -->
    21   </head>
    22   
    23   <body>
    24     This is my mmzs JSP page. <br>
    25   </body>
    26 </html>
    index.jsp

      部署工程,测试是否可以部署成功。若成功访问请进入下一步:

    2、接下来写一个登陆:

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'login.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
    
      </head>
      
      <body>
        <span style="font-size: 22px;font-weight: bolder;color: red">用户登陆</span>
        <hr color="green" size="2" width="100%" />
        <form id="loginForm" action="/BigData6-1/userAction" method="post">
            <input type="hidden" name="method" value="login">
            <input name="userName" ><br><br>
            <input name="passWord" type="password"  ><br><br>
            <input type="submit" value="登录">
        </form>
      </body>
    </html>
    login.jsp
    工程结构: 

    建立一个action基础类:

     1 package com.mmzs.bigdata.action;
     2 
     3 import java.io.IOException;
     4 import java.lang.reflect.InvocationTargetException;
     5 import java.lang.reflect.Method;
     6 
     7 import javax.servlet.ServletException;
     8 import javax.servlet.http.HttpServlet;
     9 import javax.servlet.http.HttpServletRequest;
    10 import javax.servlet.http.HttpServletResponse;
    11 
    12 public class BaseAction extends HttpServlet{
    13 
    14     @Override
    15     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    16             throws ServletException, IOException {
    17         this.doPost(req, resp);
    18     }
    19 
    20     @Override
    21     protected void doPost(HttpServletRequest request, HttpServletResponse response)
    22             throws ServletException, IOException {
    23         //获取当前客户端需要调用的逻辑控制方法
    24         String methodName = request.getParameter("method");
    25         if (null == methodName || methodName.trim().isEmpty()) return;
    26         //获取当前客户端正在调用的Servlet类
    27         Class actionClass = this.getClass();
    28         try {
    29             //从当前正在调用的Servlet类中查找需要调用的方法
    30             Method method = actionClass.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
    31             
    32             //打破方法的封装权限
    33             method.setAccessible(true);
    34             
    35             //调用控制器方法
    36             method.invoke(this, request, response);
    37         } catch (NoSuchMethodException e) {
    38             e.printStackTrace();
    39         } catch (SecurityException e) {
    40             e.printStackTrace();
    41         } catch (IllegalAccessException e) {
    42             e.printStackTrace();
    43         } catch (IllegalArgumentException e) {
    44             e.printStackTrace();
    45         } catch (InvocationTargetException e) {
    46             e.printStackTrace();
    47         }
    48         
    49     }
    50 
    51 }
    BaseAction
    这里要注意一下,doGet方法中调用doPost需要使用this.doPost(req, resp); 
    然后启动tomcat访问http://localhost:8080/BigData6-1/userAction?method=login
     3、建立我们需要的数据库:
    CREATE TABLE t_user(
    userId INT(11) PRIMARY KEY auto_increment,
    userName VARCHAR(30) not NULL,
    `passWord` VARCHAR(30) not NULL,
    realName VARCHAR(30) default null,
    weight DOUBLE(6,2) default null,
    height INT(3) default null,
    birthday DATE default null
    )ENGINE=INNODB CHARSET=utf8; 
    
    SELECT * FROM t_user;
    
    INSERT INTO t_user VALUES
    (1,'ligang','123456','李刚',65.55,176,'1997-6-6'),
    创建数据库的sql语句

    在工程中导入jar包:mysql-connector-java-3.0.17-ga-bin.jar 

    在工程中建立与数据库对应的po类:

    package com.mmzs.bigdata.po;
    
    import java.io.Serializable;
    import java.sql.Date;
    
    public class User implements Serializable {
        //支持序列化才能在磁盘之间转化为二进制进行传输
        private Integer userId;
        private String userName;
        private String passWord;
        private String realName;
        private Double weight;
        private Integer height;
        private Date birthday;
        
        public Integer getUserId() {
            return userId;
        }
        public void setUserId(Integer userId) {
            this.userId = userId;
        }
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassWord() {
            return passWord;
        }
        public void setPassWord(String passWord) {
            this.passWord = passWord;
        }
        public String getRealName() {
            return realName;
        }
        public void setRealName(String realName) {
            this.realName = realName;
        }
        public Double getWeight() {
            return weight;
        }
        public void setWeight(Double weight) {
            this.weight = weight;
        }
        public Integer getHeight() {
            return height;
        }
        public void setHeight(Integer height) {
            this.height = height;
        }
        public Date getBirthday() {
            return birthday;
        }
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
        
        @Override
        public String toString() {
            return "User [userId=" + userId + ", userName=" + userName
                    + ", passWord=" + passWord + ", realName=" + realName
                    + ", weight=" + weight + ", height=" + height + ", birthday="
                    + birthday + "]";
        }
        
        
    }
    User
    4、建立dao层
      1 package com.mmzs.bigdata.dao;
      2 
      3 import java.lang.reflect.InvocationTargetException;
      4 import java.lang.reflect.Method;
      5 import java.sql.Connection;
      6 import java.sql.DriverManager;
      7 import java.sql.PreparedStatement;
      8 import java.sql.ResultSet;
      9 import java.sql.ResultSetMetaData;
     10 import java.sql.SQLException;
     11 import java.util.ArrayList;
     12 import java.util.Date;
     13 import java.util.List;
     14 import java.util.Map;
     15 
     16 import com.mysql.jdbc.Field;
     17 
     18 public class BaseDao {
     19     
     20     private static String url;
     21     
     22     private static String driver;
     23     
     24     private static String userName;
     25     
     26     private static String passWord;
     27     
     28     static {
     29         url = "jdbc:mysql://127.0.0.1:3306/test?useUnique=true&characterEncoding=utf8";
     30         driver="com.mysql.jdbc.Driver";
     31         userName = "root";
     32         passWord = "123456";
     33         
     34         try {
     35             Class.forName(driver);
     36         } catch (ClassNotFoundException e) {
     37             e.printStackTrace();
     38         }
     39     }
     40     
     41     /**
     42      * 返回数据库链接
     43      * @return
     44      */
     45     public Connection getConnection() {
     46         Connection conn = null;
     47         try {
     48             conn = DriverManager.getConnection(url, userName, passWord);
     49         } catch (SQLException e) {
     50             e.printStackTrace();
     51         }
     52         
     53         return conn;
     54     }
     55     
     56     public <T> List<T> getEntityList(Class<T> entityClass, String sql, Object... params) {
     57         //获取数据库连接
     58         Connection conn = getConnection();
     59         if (null == conn) {
     60             return null;
     61         }
     62         //
     63         ResultSet res = null;
     64         //对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的
     65         PreparedStatement pstat = null;//import java.sql.PreparedStatement;
     66         List<T> list = new ArrayList<>();
     67         try {
     68             //预编译SQL语句
     69             pstat = conn.prepareStatement(sql);
     70             //为预编译好的SQL语句传递参数
     71             for (int i = 0; i < params.length; i++) {
     72                 pstat.setObject(i+1, params[i]);
     73             }
     74             //执行SQL语句并返回结果集
     75             res = pstat.executeQuery();
     76             //获取结果集元数据
     77             ResultSetMetaData rsmd = res.getMetaData();
     78             //获取结果集中列的数量(字段的数量)
     79             Integer columnNum = rsmd.getColumnCount();
     80             
     81             //简单类型包括数字类型、字符串类型和日期类型
     82             if (String.class.isAssignableFrom(entityClass) ||
     83                     Number.class.isAssignableFrom(entityClass) ||
     84                     Date.class.isAssignableFrom(entityClass)) {//简单类型
     85                 T t = null;
     86                 //遍历每一条记录
     87                 while (res.next()) {
     88                     //类型转换必须类型兼容;低类型向高类型自动转换,反之强制转换;
     89                     t = (T)res.getObject(1);//返回单例,索引只能去1
     90                     list.add(t);
     91                 }
     92             }else if(Map.class.isAssignableFrom(entityClass)) {//字典类型,Map是顶层接口
     93                 T t = null;
     94                 //获取的是类自身声明的所有方法
     95                 Method putMethod = entityClass.getDeclaredMethod("put", Object.class, Object.class);
     96                 while (res.next()) {
     97                     //调用反射调用Map实现累的无参数构造创建Map实例对象
     98                     t = entityClass.newInstance();
     99                     //循环每条记录中的各个字段
    100                     for (int i = 0; i < columnNum; i++) {
    101                         //获取列名(它对应于Map中的Key)
    102                         String fieldName = rsmd.getColumnLabel(i+1);
    103                         //获取列值(它对应于Map中的Value)
    104                         Object fieldValue = res.getObject(fieldName);
    105                         //调用put方法往Map中添加键值对
    106                         putMethod.invoke(t, fieldName, fieldValue);
    107                     }
    108                     list.add(t);
    109                 }
    110             }else { //实体类型
    111                 T t = null;
    112                 while (res.next()) {
    113                     //使用反射调用实体类的无参数构造创建实体对象
    114                     t = entityClass.newInstance();
    115                     for (int i = 0; i < columnNum; i++) {
    116                         //获取结果集中的字段名(或别名)
    117                         String fieldName = rsmd.getColumnLabel(i+1);
    118                         //1.根据字段名获取字段值
    119                         Object fieldValue = res.getObject(fieldName);
    120                         //2.根据索引获取字段值
    121                         //Object fieldValue = res.getObject(i+1);
    122                         //getDeclaredField是可以获取一个类的所有字段. 
    123                         //通过反射根据字段名查找实体类(User类)中的属性
    124                         java.lang.reflect.Field field = entityClass.getDeclaredField(fieldName);
    125                         //打开访问权限
    126                         field.setAccessible(true);
    127                         field.set(t, fieldValue);
    128                     }
    129                     list.add(t);
    130                 }
    131             }
    132             return list;
    133         } catch (SQLException e) {
    134             e.printStackTrace();
    135         } catch (NoSuchMethodException e) {
    136             e.printStackTrace();
    137         } catch (SecurityException e) {
    138             e.printStackTrace();
    139         } catch (InstantiationException e) {
    140             e.printStackTrace();
    141         } catch (IllegalAccessException e) {
    142             e.printStackTrace();
    143         } catch (IllegalArgumentException e) {
    144             e.printStackTrace();
    145         } catch (InvocationTargetException e) {
    146             e.printStackTrace();
    147         } catch (NoSuchFieldException e) {
    148             e.printStackTrace();
    149         }finally {
    150             try {
    151                 if (null != res) {
    152                         res.close();
    153                 }
    154                 if (null != pstat) {
    155                     pstat.close();
    156                 }
    157                 if (null != conn) {
    158                     conn.close();
    159                 }
    160             } catch (SQLException e) {
    161                 e.printStackTrace();
    162             }
    163         }
    164         return null;
    165     }
    166     
    167     
    168     
    169     
    170     
    171     
    172 //    public static void main(String[] args) {
    173 //        Connection conn = new BaseDao().getConnection();
    174 //        System.err.println(conn);
    175 //    }
    176 }
    BaseDao
    1 package com.mmzs.bigdata.dao;
    2 
    3 import com.mmzs.bigdata.po.User;
    4 
    5 public interface UserDao {
    6     public User selectUser(String userName, String passWord);
    7 }
    UserDao
     1 package com.mmzs.bigdata.dao;
     2 
     3 import java.util.List;
     4 
     5 import com.mmzs.bigdata.po.User;
     6 
     7 public class UserDaoImpl extends BaseDao implements UserDao {
     8 
     9     @Override
    10     public User selectUser(String userName, String passWord) {
    11         
    12         String sql = "select * from t_user where userName=? and passWord=?";
    13         List<User> userlist = this.getEntityList(User.class, sql, userName, passWord);
    14         
    15         return null!= userlist&&!userlist.isEmpty()?userlist.get(0):null;
    16     }
    17 
    18     
    19     
    20     public static void main(String[] args) {
    21         User user = new UserDaoImpl().selectUser("ligang", "123456");
    22         System.err.println(user);
    23     }
    24 }
    UserDaoImpl

     在UserDaoImpl中利用20-23行代码测试是否能从数据库中取到数据。

     5、建立service层

    1 package com.mmzs.bigdata.service;
    2 
    3 import com.mmzs.bigdata.po.User;
    4 
    5 public interface UserService {
    6     public User getUser(String userName, String passWord);
    7 }
    UserService
     1 package com.mmzs.bigdata.service;
     2 
     3 import com.mmzs.bigdata.po.User;
     4 
     5 public class UserServiceImpl implements UserService {
     6 
     7     @Override
     8     public User getUser(String userName, String passWord) {
     9         
    10         return null;
    11     }
    12 
    13 }
    UserServiceImpl
     6、写自己的action类
     1 package com.mmzs.bigdata.action;
     2 
     3 import javax.servlet.http.HttpServletRequest;
     4 import javax.servlet.http.HttpServletResponse;
     5 
     6 /**
     7  * 用户模块控制器
     8  * @author Administrator
     9  *
    10  */
    11 public class UserAction extends BaseAction {
    12     
    13     /**
    14      * 用户登录
    15      * @param request
    16      * @param response
    17      */
    18     public void login(HttpServletRequest request, HttpServletResponse response) {
    19         String userName = request.getParameter("userName");
    20         String passWord = request.getParameter("passWord");
    21         System.out.println(userName+":"+passWord);
    22     }
    23 }
    UserAction

     将userAction配置到web.xml文件中

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
     3     <display-name>BigData6-1</display-name>
     4     
     5     <servlet>
     6         <servlet-name>userAction</servlet-name>
     7         <servlet-class>com.mmzs.bigdata.action.UserAction</servlet-class>
     8     </servlet>
     9     
    10     <servlet-mapping>
    11         <servlet-name>userAction</servlet-name>
    12         <url-pattern>/userAction</url-pattern>
    13     </servlet-mapping>
    14     
    15     
    16     
    17     
    18     
    19     
    20     <welcome-file-list>
    21         <welcome-file>index.jsp</welcome-file>
    22     </welcome-file-list>
    23 </web-app>
    web.xml

    ==========这是华丽的分割线============

    发现自己的BaseDao中getEntityList方法名字不优美;换成executeDQL,同时它的子类UserDaoImpl也作相应的修改;同时url后面传递的参数名子也做了优化。

    然后继续封装其它的方法,继续完善BaseDao:

      1 package com.mmzs.bigdata.dao;
      2 
      3 import java.lang.reflect.InvocationTargetException;
      4 import java.lang.reflect.Method;
      5 import java.sql.Connection;
      6 import java.sql.DriverManager;
      7 import java.sql.PreparedStatement;
      8 import java.sql.ResultSet;
      9 import java.sql.ResultSetMetaData;
     10 import java.sql.SQLException;
     11 import java.util.ArrayList;
     12 import java.util.Date;
     13 import java.util.List;
     14 import java.util.Map;
     15 
     16 import com.mysql.jdbc.Field;
     17 
     18 public class BaseDao {
     19     //URL指向要访问的数据库名mydata
     20     private static String url;
     21     //驱动程序名
     22     private static String driver;
     23     //MySQL配置时的用户名
     24     private static String userName;
     25     //MySQL配置时的密码
     26     private static String passWord;
     27     /**
     28      * 连接数据库的驱动
     29      */
     30     static {
     31         url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8";
     32         driver="com.mysql.jdbc.Driver";
     33         userName = "root";
     34         passWord = "123456";
     35         try {
     36             Class.forName(driver);//加载驱动类
     37         } catch (ClassNotFoundException e) {
     38             e.printStackTrace();
     39         }
     40     }
     41     
     42     /**
     43      * 返回数据库链接
     44      * @return
     45      */
     46     public Connection getConnection() {
     47         Connection conn = null;
     48         try {
     49             conn = DriverManager.getConnection(url, userName, passWord);
     50         } catch (SQLException e) {
     51             e.printStackTrace();
     52         }
     53         
     54         return conn;
     55     }
     56     
     57     /**
     58      * 执行通用插入操作
     59      * @param pkClass
     60      * @param sql
     61      * @param params
     62      * @return 主键列表(主键列表的长度代表插入函数的影响函数)
     63      */
     64     public <T> List<T> executeInsert(Class<T> pkClass, String sql, Object... params) {
     65         //获取数据库连接
     66         Connection conn = getConnection();
     67         if (null == conn) return null;
     68         
     69         T t = null;
     70         ResultSet pkRes = null;
     71         PreparedStatement pstat = null;
     72         List<T> pkList = new ArrayList<T>();
     73         try {
     74             //预编译SQL语句
     75             pstat = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
     76             //为预编译好的SQL语句传递参数
     77             for (int i = 0; i < params.length; i++) {
     78                 pstat.setObject(i+1, params[i]);
     79             }
     80             //执行增删改等操作返回影响的行数
     81             pstat.executeUpdate();
     82             //获取生成的主键结果集
     83             pkRes = pstat.getGeneratedKeys();
     84             //遍历主键结果集
     85             while (pkRes.next()) {
     86                 //主键结果集中的每一条记录只有一列(这一列代表主键值),所以只能取下标1
     87                 t = (T) pkRes.getObject(1);
     88                 pkList.add(t);
     89             }
     90             return pkList;
     91             
     92         } catch (SQLException e) {
     93             e.printStackTrace();
     94         }finally {
     95             try {
     96                 if (null != pkRes) {
     97                     pkRes.close();
     98                 }
     99                 if (null != pstat) {
    100                     pstat.close();
    101                 }
    102                 if (null != conn) {
    103                     conn.close();
    104                 }
    105             } catch (SQLException e) {
    106                 e.printStackTrace();
    107             }
    108         }
    109         
    110         return null;
    111     }
    112     
    113     /**
    114      * 执行通用的增删改
    115      * @param sql
    116      * @param params
    117      * @return 影响行数
    118      */
    119     public Integer executeDML(String sql, Object... params) {
    120         //获取数据库连接
    121         Connection conn = getConnection();
    122         if (null == conn) return null;
    123         
    124         Integer count = null;
    125         PreparedStatement pstat = null;
    126         //为预编译好的SQL语句传递参数
    127         try {
    128             //预编译SQL语句
    129             pstat = conn.prepareStatement(sql);
    130             //为预编译好的SQL语句传递参数
    131             for (int i = 0; i < params.length; i++) {
    132                 pstat.setObject(i+1, params[i]);
    133             }
    134             //执行增删改等操作
    135             count = pstat.executeUpdate();
    136             return count;
    137             
    138         } catch (SQLException e) {
    139             e.printStackTrace();
    140         }finally {
    141             try {
    142                 if (null != pstat) {
    143                     pstat.close();
    144                 }
    145                 if (null != conn) {
    146                     conn.close();
    147                 }
    148             } catch (SQLException e) {
    149                 e.printStackTrace();
    150             }
    151         }
    152         return 0;
    153     }
    154     
    155     /**
    156      * 执行数据库查询操作
    157      * @param entityClass
    158      * @param sql
    159      * @param params
    160      * @return 结果集
    161      */
    162     public <T> List<T> executeDQL(Class<T> entityClass, String sql, Object... params) {
    163         //获取数据库连接
    164         Connection conn = getConnection();
    165         if (null == conn) {
    166             return null;
    167         }
    168         //
    169         ResultSet res = null;
    170         //对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的
    171         PreparedStatement pstat = null;//import java.sql.PreparedStatement;
    172         List<T> list = new ArrayList<>();
    173         try {
    174             //预编译SQL语句
    175             pstat = conn.prepareStatement(sql);
    176             //为预编译好的SQL语句传递参数
    177             for (int i = 0; i < params.length; i++) {
    178                 pstat.setObject(i+1, params[i]);
    179             }
    180             //执行SQL语句并返回结果集
    181             res = pstat.executeQuery();
    182             //获取结果集元数据
    183             ResultSetMetaData rsmd = res.getMetaData();
    184             //获取结果集中列的数量(字段的数量)
    185             Integer columnNum = rsmd.getColumnCount();
    186             
    187             //简单类型包括数字类型、字符串类型和日期类型
    188             if (String.class.isAssignableFrom(entityClass) ||
    189                     Number.class.isAssignableFrom(entityClass) ||
    190                     Date.class.isAssignableFrom(entityClass)) {//简单类型
    191                 T t = null;
    192                 //遍历每一条记录
    193                 while (res.next()) {
    194                     //类型转换必须类型兼容;低类型向高类型自动转换,反之强制转换;
    195                     t = (T)res.getObject(1);//返回单例,索引只能去1
    196                     list.add(t);
    197                 }
    198             }else if(Map.class.isAssignableFrom(entityClass)) {//字典类型,Map是顶层接口
    199                 T t = null;
    200                 //获取的是类自身声明的所有方法
    201                 Method putMethod = entityClass.getDeclaredMethod("put", Object.class, Object.class);
    202                 while (res.next()) {
    203                     //调用反射调用Map实现累的无参数构造创建Map实例对象
    204                     t = entityClass.newInstance();
    205                     //循环每条记录中的各个字段
    206                     for (int i = 0; i < columnNum; i++) {
    207                         //获取列名(它对应于Map中的Key)
    208                         String fieldName = rsmd.getColumnLabel(i+1);
    209                         //获取列值(它对应于Map中的Value)
    210                         Object fieldValue = res.getObject(fieldName);
    211                         //调用put方法往Map中添加键值对
    212                         putMethod.invoke(t, fieldName, fieldValue);
    213                     }
    214                     list.add(t);
    215                 }
    216             }else { //实体类型
    217                 T t = null;
    218                 while (res.next()) {
    219                     //使用反射调用实体类的无参数构造创建实体对象
    220                     t = entityClass.newInstance();
    221                     for (int i = 0; i < columnNum; i++) {
    222                         //获取结果集中的字段名(或别名)
    223                         String fieldName = rsmd.getColumnLabel(i+1);
    224                         //1.根据字段名获取字段值
    225                         Object fieldValue = res.getObject(fieldName);
    226                         //2.根据索引获取字段值
    227                         //Object fieldValue = res.getObject(i+1);
    228                         //getDeclaredField是可以获取一个类的所有字段. 
    229                         //通过反射根据字段名查找实体类(User类)中的属性
    230                         java.lang.reflect.Field field = entityClass.getDeclaredField(fieldName);
    231                         //打开访问权限
    232                         field.setAccessible(true);
    233                         field.set(t, fieldValue);
    234                     }
    235                     list.add(t);
    236                 }
    237             }
    238             return list;
    239         } catch (SQLException e) {
    240             e.printStackTrace();
    241         } catch (NoSuchMethodException e) {
    242             e.printStackTrace();
    243         } catch (SecurityException e) {
    244             e.printStackTrace();
    245         } catch (InstantiationException e) {
    246             e.printStackTrace();
    247         } catch (IllegalAccessException e) {
    248             e.printStackTrace();
    249         } catch (IllegalArgumentException e) {
    250             e.printStackTrace();
    251         } catch (InvocationTargetException e) {
    252             e.printStackTrace();
    253         } catch (NoSuchFieldException e) {
    254             e.printStackTrace();
    255         }finally {
    256             try {
    257                 if (null != res) {
    258                         res.close();
    259                 }
    260                 if (null != pstat) {
    261                     pstat.close();
    262                 }
    263                 if (null != conn) {
    264                     conn.close();
    265                 }
    266             } catch (SQLException e) {
    267                 e.printStackTrace();
    268             }
    269         }
    270         return null;
    271     }
    272     
    273     
    274     
    275     
    276     
    277     
    278 //    public static void main(String[] args) {
    279 //        Connection conn = new BaseDao().getConnection();
    280 //        System.err.println(conn);
    281 //    }
    282 }
    BaseDao

    在UserDaoImpl中测试:

     1 package com.mmzs.bigdata.dao;
     2 
     3 import java.sql.Date;
     4 import java.util.List;
     5 
     6 import com.mmzs.bigdata.po.User;
     7 
     8 public class UserDaoImpl extends BaseDao implements UserDao {
     9 
    10     @Override
    11     public User selectUser(String userName, String passWord) {
    12         
    13         String sql = "select * from t_user where userName=? and passWord=?";
    14         List<User> userlist = this.executeDQL(User.class, sql, userName, passWord);
    15         
    16         return null!= userlist&&!userlist.isEmpty()?userlist.get(0):null;
    17     }
    18 
    19     
    20     
    21     /**
    22      * @param args
    23      */
    24     public static void main(String[] args) {
    25         //测试executeDQL
    26 //        User user = new UserDaoImpl().selectUser("ligang", "123456");
    27 //        System.out.println(user);
    28     
    29         //测试executeInsert
    30 //        String sql = "insert into t_user(username,password,realname,weight,height,birthday) values(?,?,?,?,?,?),(?,?,?,?,?,?)";
    31 //        List<Integer> pkList =  new UserDaoImpl().executeInsert(Integer.class, sql, "zhangsan","123456","张三",75.55,176,Date.valueOf("1997-6-6"),"lisi","lisi","张三",55.55,176,Date.valueOf("2005-6-6"));
    32 //        System.out.println("主键列表:"+pkList);
    33 //        System.out.println("影响行数:"+pkList.size());
    34         
    35         //测试executeDML
    36         String sql = "update t_user set username=?,password=?,realname=?,weight=?,height=?,birthday=? where userid=?";
    37         Integer count =  new UserDaoImpl().executeDML( sql, "ligang","123456","张三",75.55,176,Date.valueOf("1997-6-6"),1);
    38         System.out.println("影响行数:"+count);
    39     }
    40 }
    UserDaoImpl

    ==========这是华丽的分割线============

    发现自己的BaseDao中的连接数据库的部分写的太固定;比如你需要修改密码时,需要改源代码,然后提交到运维测试,需要走一大圈流程;所以接下来我们把连接数据库的部分写到一个文本中,这样子需要修改时就不需要修改源代码了;

    首先将如下代码进行一定修改,写到src下的db.properties中:

    url = "jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8";
    driver="com.mysql.jdbc.Driver";
    userName = "root";
    passWord = "123456";
    需修改部分

     在db.properties文件中时以键值对的形式存储的;以第一个等号为分界线,默认左右都为字符串,=左边为键,右边为值;为了便于阅读,如使用的是jdbc的,就用jdbc.xxx

    jdbc.url = jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.userName = root
    jdbc.passWord =123456
    db.properties
    package com.mmzs.bigdata.dao;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.Map;
    import java.util.Properties;
    
    public class BaseDao {
        //URL指向要访问的数据库名mydata
        private static String url;
        //驱动程序名
        private static String driver;
        //MySQL配置时的用户名
        private static String userName;
        //MySQL配置时的密码
        private static String passWord;
        /**
         * 连接数据库的驱动
         */
        static {
            try {
                Properties properties = new Properties();
                
                //此处/表示src根路径;创建指向磁盘文件中属性文件的输入流
                InputStream fis = BaseDao.class.getResourceAsStream("/db.properties");
                //将属性文件中的内容从磁盘读入到内存中
                properties.load(fis);
                //取连接数据库的参数值
                url = properties.getProperty("jdbc.url");
                driver = properties.getProperty("jdbc.driver");
                userName = properties.getProperty("jdbc.userName");
                passWord = properties.getProperty("jdbc.passWord");
                //将驱动类装载到JVM内存的方法区
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        /**
         * 返回数据库链接
         * @return
         */
        public Connection getConnection() {
            Connection conn = null;
            try {
                conn = DriverManager.getConnection(url, userName, passWord);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
            return conn;
        }
        
        /**
         * 执行通用插入操作
         * @param pkClass
         * @param sql
         * @param params
         * @return 主键列表(主键列表的长度代表插入函数的影响函数)
         */
        public <T> List<T> executeInsert(Class<T> pkClass, String sql, Object... params) {
            //获取数据库连接
            Connection conn = getConnection();
            if (null == conn) return null;
            
            T t = null;
            ResultSet pkRes = null;
            PreparedStatement pstat = null;
            List<T> pkList = new ArrayList<T>();
            try {
                //预编译SQL语句
                pstat = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
                //为预编译好的SQL语句传递参数
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
                //执行增删改等操作返回影响的行数
                pstat.executeUpdate();
                //获取生成的主键结果集
                pkRes = pstat.getGeneratedKeys();
                //遍历主键结果集
                while (pkRes.next()) {
                    //主键结果集中的每一条记录只有一列(这一列代表主键值),所以只能取下标1
                    t = (T) pkRes.getObject(1);
                    pkList.add(t);
                }
                return pkList;
                
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (null != pkRes) {
                        pkRes.close();
                    }
                    if (null != pstat) {
                        pstat.close();
                    }
                    if (null != conn) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            
            return null;
        }
        
        /**
         * 执行通用的增删改
         * @param sql
         * @param params
         * @return 影响行数
         */
        public Integer executeDML(String sql, Object... params) {
            //获取数据库连接
            Connection conn = getConnection();
            if (null == conn) return null;
            
            Integer count = null;
            PreparedStatement pstat = null;
            //为预编译好的SQL语句传递参数
            try {
                //预编译SQL语句
                pstat = conn.prepareStatement(sql);
                //为预编译好的SQL语句传递参数
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
                //执行增删改等操作
                count = pstat.executeUpdate();
                return count;
                
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (null != pstat) {
                        pstat.close();
                    }
                    if (null != conn) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return 0;
        }
        
        /**
         * 执行数据库查询操作
         * @param entityClass
         * @param sql
         * @param params
         * @return 结果集
         */
        public <T> List<T> executeDQL(Class<T> entityClass, String sql, Object... params) {
            //获取数据库连接
            Connection conn = getConnection();
            if (null == conn) {
                return null;
            }
            //
            ResultSet res = null;
            //对于只执行一次的SQL语句选择Statement是最好的. 相反, 如果SQL语句被多次执行选用PreparedStatement是最好的
            PreparedStatement pstat = null;//import java.sql.PreparedStatement;
            List<T> list = new ArrayList<>();
            try {
                //预编译SQL语句
                pstat = conn.prepareStatement(sql);
                //为预编译好的SQL语句传递参数
                for (int i = 0; i < params.length; i++) {
                    pstat.setObject(i+1, params[i]);
                }
                //执行SQL语句并返回结果集
                res = pstat.executeQuery();
                //获取结果集元数据
                ResultSetMetaData rsmd = res.getMetaData();
                //获取结果集中列的数量(字段的数量)
                Integer columnNum = rsmd.getColumnCount();
                
                //简单类型包括数字类型、字符串类型和日期类型
                if (String.class.isAssignableFrom(entityClass) ||
                        Number.class.isAssignableFrom(entityClass) ||
                        Date.class.isAssignableFrom(entityClass)) {//简单类型
                    T t = null;
                    //遍历每一条记录
                    while (res.next()) {
                        //类型转换必须类型兼容;低类型向高类型自动转换,反之强制转换;
                        t = (T)res.getObject(1);//返回单例,索引只能去1
                        list.add(t);
                    }
                }else if(Map.class.isAssignableFrom(entityClass)) {//字典类型,Map是顶层接口
                    T t = null;
                    //获取的是类自身声明的所有方法
                    Method putMethod = entityClass.getDeclaredMethod("put", Object.class, Object.class);
                    while (res.next()) {
                        //调用反射调用Map实现累的无参数构造创建Map实例对象
                        t = entityClass.newInstance();
                        //循环每条记录中的各个字段
                        for (int i = 0; i < columnNum; i++) {
                            //获取列名(它对应于Map中的Key)
                            String fieldName = rsmd.getColumnLabel(i+1);
                            //获取列值(它对应于Map中的Value)
                            Object fieldValue = res.getObject(fieldName);
                            //调用put方法往Map中添加键值对
                            putMethod.invoke(t, fieldName, fieldValue);
                        }
                        list.add(t);
                    }
                }else { //实体类型
                    T t = null;
                    while (res.next()) {
                        //使用反射调用实体类的无参数构造创建实体对象
                        t = entityClass.newInstance();
                        for (int i = 0; i < columnNum; i++) {
                            //获取结果集中的字段名(或别名)
                            String fieldName = rsmd.getColumnLabel(i+1);
                            //1.根据字段名获取字段值
                            Object fieldValue = res.getObject(fieldName);
                            //2.根据索引获取字段值
                            //Object fieldValue = res.getObject(i+1);
                            //getDeclaredField是可以获取一个类的所有字段. 
                            //通过反射根据字段名查找实体类(User类)中的属性
                            java.lang.reflect.Field field = entityClass.getDeclaredField(fieldName);
                            //打开访问权限
                            field.setAccessible(true);
                            field.set(t, fieldValue);
                        }
                        list.add(t);
                    }
                }
                return list;
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }finally {
                try {
                    if (null != res) {
                            res.close();
                    }
                    if (null != pstat) {
                        pstat.close();
                    }
                    if (null != conn) {
                        conn.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
        
    }
    BaseDao

    ==========这是华丽的分割线============

    接下我们尝试将sql语句写到文本文件中来读取,优点同上;

    首先,在工程中导入jar包:xstream-all-1.4.7.jar;
    然后,在UserDaoImpl 中测试xstream包的一些用法;
    package com.mmzs.bigdata.dao;
    
    import java.sql.Date;
    import java.util.List;
    
    import com.mmzs.bigdata.po.User;
    
    public class UserDaoImpl extends BaseDao implements UserDao {
    
        @Override
        public User selectUser(String userName, String passWord) {
            
            String sql = "select * from t_user where userName=? and passWord=?";
            List<User> userlist = this.executeDQL(User.class, sql, userName, passWord);
            
            return null!= userlist&&!userlist.isEmpty()?userlist.get(0):null;
        }
    
        
        
        /**
         * 测试xml的相关操作
         */
        public static void main(String[] args) {
    
            Map<String, Object> user = new HashMap<String, Object>();
            user.put("userId", 12);
            user.put("userName", "ligang");
            user.put("passWord", "liagan");
            
            
            System.out.println("======序列化======");
            XStream stream = new XStream();
            String xml = stream.toXML(user);
            System.out.println(xml);
            
            System.out.println("======反序列化======");
            Map<String, Object> newUser = (Map<String, Object>) stream.fromXML(xml);
            String userName = (String) newUser.get("userName"); 
            System.out.println(newUser+"==="+userName);
        }
    }
    UserDaoImpl

     最后,在src下面新建sql.xml;

    <?xml version="1.0" encoding="UTF-8"?>
    <map>
      <entry>
        <string>selectUser</string>
        <string>select * from t_user where userName=? and passWord=?</string>
      </entry>
    </map>
    sql.xml

    在UserDaoImpl 中进行最终测试;

    package com.mmzs.bigdata.dao;
    
    import java.io.InputStream;
    import java.sql.Date;
    
    public class UserDaoImpl extends BaseDao implements UserDao {
    
        private Map<String, String> sqlMap;
        
        public UserDaoImpl() {
            XStream stream = new XStream();
            InputStream fis = UserDao.class.getResourceAsStream("/sql.xml");
            sqlMap = (Map<String, String>) stream.fromXML(fis);
        }
        
        @Override
        public User selectUser(String userName, String passWord) {
            
            String sql = sqlMap.get("selectUser");
            List<User> userlist = this.executeDQL(User.class, sql, userName, passWord);
            
            return null!= userlist&&!userlist.isEmpty()?userlist.get(0):null;
        }
        
    
        
        public static void main(String[] args) {
            
             User user = new UserDaoImpl().selectUser("ligang", "123456");
             System.out.println(user);
            
        }
    }
    UserDaoImpl

    ==========这是华丽的分割线============

     现在准备工作就绪,我们开始写登录页面进行登陆验证:

    因为Dao层已经写完了,所以直接开始写Service实现层:

     1 package com.mmzs.bigdata.service;
     2 
     3 import com.mmzs.bigdata.dao.UserDao;
     4 import com.mmzs.bigdata.dao.UserDaoImpl;
     5 import com.mmzs.bigdata.po.User;
     6 
     7 public class UserServiceImpl implements UserService {
     8 
     9     private UserDao userDao;
    10     
    11     public UserServiceImpl() {
    12         userDao = new UserDaoImpl();
    13     }
    14     
    15     
    16     @Override
    17     public User getUser(String userName, String passWord) {
    18         return userDao.selectUser(userName, passWord);
    19     }
    20 
    21 }
    UserServiceImpl

    然后完善UserAction类: 

     1 package com.mmzs.bigdata.action;
     2 
     3 import java.io.IOException;
     4 
     5 import javax.servlet.ServletException;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import com.mmzs.bigdata.po.User;
    10 import com.mmzs.bigdata.service.UserService;
    11 import com.mmzs.bigdata.service.UserServiceImpl;
    12 
    13 /**
    14  * 用户模块控制器
    15  * @author Administrator
    16  *
    17  */
    18 public class UserAction extends BaseAction {
    19     
    20     private UserService userService;
    21     
    22     public UserAction() {
    23         userService = new UserServiceImpl();
    24     }
    25     /**
    26      * 用户登录
    27      * @param request
    28      * @param response
    29      * @throws IOException 
    30      * @throws ServletException 
    31      */
    32     public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    33         String userName = request.getParameter("userName");
    34         String passWord = request.getParameter("passWord");
    35         User user = userService.getUser(userName, passWord);
    36         if (null != user) {//登陆成功
    37             request.getSession().setAttribute("loginUser", user);
    38             request.getRequestDispatcher("/main.jsp").forward(request, response);
    39             System.out.println("登陆成功!");
    40             return;//如果你是一个比较有良知的人,加一个return;因为加了执行到此处就结束,否则会往下执行自动结束;理论上加与不加效果相同;
    41         } else {//登录失败
    42             request.setAttribute("loginError", "用户名或密码输入错误");
    43             request.getRequestDispatcher("/login.jsp").forward(request, response);
    44         }
    45     }
    46 }
    UserAction

     写出UserAction类成功和失败返回的界面:

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'login.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
    
      </head>
      
      <body>
        
      </body>
    </html>
    登陆成功!
    main.jsp
    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <base href="<%=basePath%>">
        
        <title>My JSP 'login.jsp' starting page</title>
        
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">    
        <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
        <meta http-equiv="description" content="This is my page">
        <!--
        <link rel="stylesheet" type="text/css" href="styles.css">
        -->
        <script type="text/javascript">
            //用于验证登陆参数
            function validate(Form)    {
                var userName = Form.userName.value;
                var passWord = Form.passWord.value;
                
                if(""==userName || ""==passWord) {
                    alert("请完整的输入用户名和密码");
                    return false;//取消表但提交            
                }
            }
        </script>
      </head>
      
      <body>
        <span style="font-size: 22px;font-weight: bolder;color: red">用户登陆</span>
        <hr color="green" size="2" width="100%" />
        <form id="loginForm" action="/BigData6-1/userAction" method="post">
            <input type="hidden" name="method" value="login">
            <input name="userName" ><br><br>
            <input name="passWord" type="password"  ><br><br>
            <!-- 只有带了name属性的才会被提交到服务器 -->
            <input type="submit" value="登录" onclick="return validate(this.form)">
        </form>
        <span style="font-size: 14px;font-weight: bolder;color: red">${loginError }</span>
      </body>
    </html>
    login.jsp

    写到此处,整个程序整体已经比较完整了;

    ==========这是华丽的分割线============

    接下来,我们增加点用户,然后打算做一个用户列表的分页查询:

     1、首先就需要在dao层写一个查询所有用户的方法

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <map>
     3   <entry>
     4     <string>selectUser</string>
     5     <string>select * from t_user where userName=? and passWord=?</string>
     6   </entry>
     7   <entry>
     8     <string>selectUserList</string>
     9     <string>select * from t_user limit ?,?</string>
    10   </entry>
    11     <entry>
    12     <string>selectUserCount</string>
    13     <string>select count(1) from t_user</string>
    14   </entry>
    15 </map>
    UserDaoImpl中需要的sql语句文件:sql.xml
            /**
         * 根据通用查询查询用户
         * @param params
         * @return
         */
        public List<User> selectUserList(Map<String, Object> params);    
    UserDao
            @Override
        public List<User> selectUserList(Map<String, Object> params) {
            Integer start = (Integer) params.get("start");
            Integer count = (Integer) params.get("count");
            
            String sql = sqlMap.get("selectUserList");
            List<User> userList = executeDQL(User.class, sql, start, count);
            
            return userList;
        }    
    UserDaoImpl

     2、写出service层

            /**
         * @param curPage 跳转到的目标也
         * @param count 每页显示的记录数量
         * @return 分页字典对象
         */
        public Map<String, Object> getUserList(Integer curPage, Integer count);
    UserService
    package com.mmzs.bigdata.service;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import com.mmzs.bigdata.dao.UserDao;
    import com.mmzs.bigdata.dao.UserDaoImpl;
    import com.mmzs.bigdata.po.User;
    
    public class UserServiceImpl implements UserService {
    
        private UserDao userDao;
        
        public UserServiceImpl() {
            userDao = new UserDaoImpl();
        }
        
        
        @Override
        public User getUser(String userName, String passWord) {
            return userDao.selectUser(userName, passWord);
        }
    
    
        @Override
        public Map<String, Object> getUserList(Integer curPage, Integer count) {
            //计算分页的起始索引
            Integer start = (curPage-1)*count;
            
            //包装分页字典
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("start", start);
            params.put("count", count);
            
            //通过分页参数查询分页数据
            List<User> userList = userDao.selectUserList(params);
            //查询表的总记录数量
            Integer totalCount = userDao.selectUserCount();
            //计算总页数
            Integer totalPage = totalCount/count;
            if (totalCount%count != 0) {//如果有余数,则总页数加1
                totalPage++;
            }
            
            //包装分页数据字典
            Map<String, Object> resMap = new HashMap<String, Object>();
            resMap.put("userList", userList);
            resMap.put("curPage", curPage);
            resMap.put("totalPage", totalPage);
            
            
            
            return resMap;
        }
    
    }
    UserServiceImpl
     1 package com.mmzs.bigdata.action;
     2 
     3 import java.io.IOException;
     4 import java.util.HashMap;
     5 import java.util.Map;
     6 
     7 import javax.servlet.ServletException;
     8 import javax.servlet.http.HttpServletRequest;
     9 import javax.servlet.http.HttpServletResponse;
    10 
    11 import com.mmzs.bigdata.po.User;
    12 import com.mmzs.bigdata.service.UserService;
    13 import com.mmzs.bigdata.service.UserServiceImpl;
    14 
    15 /**
    16  * 用户模块控制器
    17  * @author Administrator
    18  *
    19  */
    20 public class UserAction extends BaseAction {
    21     
    22     private UserService userService;
    23     
    24     public UserAction() {
    25         userService = new UserServiceImpl();
    26     }
    27     /**
    28      * 用户登录
    29      * @param request
    30      * @param response
    31      * @throws IOException 
    32      * @throws ServletException 
    33      */
    34     public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    35         String userName = request.getParameter("userName");
    36         String passWord = request.getParameter("passWord");
    37         
    38         User user = userService.getUser(userName, passWord);
    39         if (null != user) {//登陆成功
    40             request.getSession().setAttribute("loginUser", user);
    41             Map<String, Object> resMap = userService.getUserList(1, COUNT);
    42 
    43             request.setAttribute("curPage", resMap.get("curPage"));
    44             request.setAttribute("totalPage", resMap.get("totalPage"));
    45             request.setAttribute("userList", resMap.get("userList"));
    46             System.out.println(resMap);
    47             request.getRequestDispatcher("/main.jsp").forward(request, response);
    48             return;//如果你是一个比较有良知的人,加一个return;因为加了执行到此处就结束,否则会往下执行自动结束;理论上加与不加效果相同;
    49         } else {//登录失败
    50             request.setAttribute("loginError", "用户名或密码输入错误");
    51             request.getRequestDispatcher("/login.jsp").forward(request, response);
    52         }
    53     }
    54 }
    UserAction

    每页显示的记录数量

            /**
         * 每页显示的记录数量
         */
        protected static final Integer COUNT = 5;        
    BaseAction

    在BaseAction中用一个常量固定化,分页所需要的参数:

        /**
         * 总数量
         * @return
         */
        public Integer selectUserCount();
    UserDao
        @Override
        public Integer selectUserCount() {
            String sql = sqlMap.get("selectUserCount");
            List<Long> counts = executeDQL(Long.class, sql);
            return null!= counts&&!counts.isEmpty()?counts.get(0).intValue():null;
        }
    UserDaoImpl

     写界面,并且分页所需参数名字保持一致:

     1 <%@ page language="java" pageEncoding="UTF-8"%>
     2 <script type="text/javascript">
     3     var curPage=${curPage}
     4     var totalPage=${totalPage}
     5 
     6     //首页
     7     function firstPage(){
     8         if(curPage<=1){
     9             alert("当前页已经是第一页!");
    10             return;
    11         }
    12         sepPage(1);//执行翻页(翻到第一页)
    13     }
    14     
    15     //上一页
    16     function prePage(){
    17         if(curPage<=1){
    18             alert("当前页已经是第一页!");
    19             return;
    20         }
    21         sepPage(curPage-1);//执行翻页
    22     }
    23     
    24     //下一页
    25     function nextPage(){
    26         if(curPage>=totalPage){
    27             alert("当前页已经是末页!");
    28             return;
    29         }
    30         sepPage(curPage+1);//执行翻页
    31     }
    32     
    33     //末页
    34     function lastPage(){
    35         if(curPage>=totalPage){
    36             alert("当前页已经是末页!");
    37             return;
    38         }
    39         sepPage(totalPage);//执行翻页
    40     }
    41     
    42     //跳转到
    43     function gotoPage(){
    44         var toPage=document.getElementById("toPage").value;
    45         var rex=/^d+$/
    46         if(!rex.test(toPage)||parseInt(toPage)<1||parseInt(toPage)>totalPage){
    47             alert("输入的页号不合理!");
    48             return;
    49         }
    50         if(parseInt(curPage)==parseInt(toPage)){
    51             alert("当前页已经是你输入的页号");
    52             return;
    53         }
    54         sepPage(toPage);
    55     }
    56 </script>
    57 <div style="text-align: center;">
    58     <pre style="display: inline;font-size:16px;">当前是第:${curPage}/${totalPage}页 </pre>
    59     <input type="button" value="首页" onclick="firstPage()"/>
    60     <input type="button" value="上一页" onclick="prePage()"/>
    61     <input type="button" value="下一页" onclick="nextPage()"/>
    62     <input type="button" value="末页" onclick="lastPage()"/>
    63     <input type="button" value="跳转到" onclick="gotoPage()"/>
    64     <input id="toPage" name="toPage" style="50px;"/>65 </div>
    paging.jsp
    导入分页jsp中需要的js:js.zip
    在返回的主页面回显:
     1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
     2 <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c"  %>
     3 <%
     4 String path = request.getContextPath();
     5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
     6 %>
     7 
     8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     9 <html>
    10   <head>
    11     <base href="<%=basePath%>">
    12     
    13     <title>My JSP 'login.jsp' starting page</title>
    14     
    15     <meta http-equiv="pragma" content="no-cache">
    16     <meta http-equiv="cache-control" content="no-cache">
    17     <meta http-equiv="expires" content="0">    
    18     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    19     <meta http-equiv="description" content="This is my page">
    20     <style type="text/css">
    21         table,td,th{
    22             border: 1px solid black;
    23             height: 20px;
    24         }
    25     </style>
    26 
    27   </head>
    28   
    29   <body>
    30     <span style="font-size: 22px;font-weight: bolder;color: red">用户信息表</span>
    31     <hr color="green" size="2" width="100%" />
    32     <div id="dataDiv">
    33         <table weight="600" height="400" cellpadding="0" cellspacing="0">
    34             <thead>
    35                 <tr>
    36                     <th>
    37                         <input type="checkbox" id="allSel">全选
    38                     </th>
    39                     <th>用户名</th>
    40                     <th>密码</th>
    41                     <th>姓名</th>
    42                     <th>体重</th>
    43                     <th>身高</th>
    44                     <th>生日</th>
    45                     <th>操作</th>
    46                 </tr>
    47             </thead>
    48             <tbody>
    49             <c:forEach items="${userList }" var="user" varStatus="stat">
    50                 <tr>
    51                     <td><input type="checkbox" name="userIds" value="${user.userId }"></td>
    52                     <td>${user.userName }</td>
    53                     <td>${user.passWord }</td>
    54                     <td>${user.realName }</td>
    55                     <td>${user.weight }</td>
    56                     <td>${user.height }</td>
    57                     <td>${user.birthday }</td>
    58                     <td>
    59                         <input type="button" value="删除">
    60                         <input type="button" value="修改">
    61                     </td>
    62                 </tr>
    63             </c:forEach>
    64             </tbody>
    65         </table>
    66     </div>
    67   </body>
    68 </html>
    main.jsp

     进行到此时,测试代码,成功登陆就已经能够得到用户列表了。

     ==========这是华丽的分割线============
     完善main.jsp页面:添加分页功能,实现最简单的一种分页方式;
        <script type="text/javascript">
            //分页函数
            function sepPage(toPage) {
                window.location.href="/BigData6-1/userAction?method=list&curPage="+toPage;
                
            }
        </script>
    添加script调用分页UserAction中的list方法
                           <tfoot>
                    <tr>
                        <td colspan="8">
                            <%@ include file="paging.jsp" %>
                        </td>
                    </tr>
                </tfoot>
    在main.jsp中引入paging.jsp
        /**
         * 列表分页
         * @param request
         * @param response
         * @throws IOException 
         * @throws ServletException 
         */
        public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String curPage = request.getParameter("curPage");
            Map<String, Object> resMap = userService.getUserList(Integer.parseInt(curPage), COUNT);
            
            request.setAttribute("curPage", resMap.get("curPage"));
            request.setAttribute("totalPage", resMap.get("totalPage"));
            request.setAttribute("userList", resMap.get("userList"));
            
            request.getRequestDispatcher("/main.jsp").forward(request, response);
        }
    UserAction中的list方法

     进行到此时,测试代码,成功登陆就已经能够得到用户列表并操作分页功能了。

     ==========这是华丽的分割线============
    接下来我们将数据传递方式修改成ajax的方式:
    <script type="text/javascript">
            //分页函数
            function sepPage(toPage) {
                //window.location.href="/BigData6-1/userAction?method=list&curPage="+toPage;
                //var div = $("div#dataDiv").get(0);
                //ajax回调函数
                function callBack(data){
                    $("div#dataDiv").html(data);
                }
                /*
                * A、如果需要get方式提交则可以调$.get(…)
                    B、get与post一共有四个参数:
                    第一个参数:提交的服务端地址
                    第二个参数:提交到服务端的参数
                    第三个参数:服务端成功响应回来之后的回调函数,回调函数的参数表示服务端响应回来的数据
                    第四个参数:服务端响应回来的数据格式(html、json、xml)
                */
                $.post("/BigData6-1/userAction",
                        "method=list&curPage="+toPage,
                        callBack,
                        "html")
            }
        </script>
    重写分页函数sepPage
            /**
         * 列表分页
         * @param request
         * @param response
         * @throws IOException 
         * @throws ServletException 
         */
        public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String curPage = request.getParameter("curPage");
            Map<String, Object> resMap = userService.getUserList(Integer.parseInt(curPage), COUNT);
            //大公司操作
    //        StringWriter writer = new StringWriter();
    //        ObjectMapper mapper = new ObjectMapper();
    //        mapper.writeValue(writer, resMap);
    //        String jsonString = writer.toString();
    //        response.getWriter().write(jsonString);
            
            //小公司操作
            request.setAttribute("curPage", resMap.get("curPage"));
            request.setAttribute("totalPage", resMap.get("totalPage"));
            request.setAttribute("userList", resMap.get("userList"));
            //request.getRequestDispatcher("/main.jsp").forward(request, response);
            request.getRequestDispatcher("/table.jsp").forward(request, response);
        }    
    重写UserAction中的list方法
    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"  %>
            <table weight="600" height="400" cellpadding="0" cellspacing="0">
                <thead>
                    <tr>
                        <th>
                            <input type="checkbox" id="allSel">&nbsp;全选
                        </th>
                        <th>用&nbsp;户&nbsp;名</th>
                        <th>密&nbsp;&nbsp;码</th>
                        <th>姓&nbsp;&nbsp;名</th>
                        <th>体&nbsp;&nbsp;重</th>
                        <th>身&nbsp;&nbsp;高</th>
                        <th>生&nbsp;&nbsp;日</th>
                        <th>操&nbsp;&nbsp;作</th>
                    </tr>
                </thead>
                <tbody>
                <c:forEach items="${userList }" var="user" varStatus="stat">
                    <tr>
                        <td><input type="checkbox" name="userIds" value="${user.userId }"></td>
                        <td>${user.userName }</td>
                        <td>${user.passWord }</td>
                        <td>${user.realName }</td>
                        <td>${user.weight }</td>
                        <td>${user.height }</td>
                        <td>${user.birthday }</td>
                        <td>
                            <input type="button" value="删除">
                            <input type="button" value="修改">
                        </td>
                    </tr>
                </c:forEach>
                </tbody>
                <tfoot>
                    <tr>
                        <td colspan="8">
                            <%@ include file="paging.jsp" %>
                        </td>
                    </tr>
                </tfoot>
            </table>
    添加table.jsp页面;其实就是main.jsp页面中的table部分

     进行到此时,测试代码,成功登陆就,同样能够得到用户列表并操作分页功能,只是此时我们使用的传值的方式不同了。

      ==========这是华丽的分割线============
     这时又来一个需求,用户登陆后不想全部查询出来用户,只想查询部分用户;比如查询名字带"李"的人;(%三%:表示模糊查询)
    首先需要在sql.xml中添加sql语句:
      <entry>
        <string>selectUserListByCondition</string>
        <string>select * from t_user where realName like ? limit ?,?</string>
      </entry>
      <entry>
        <string>selectUserCountByCondition</string>
        <string>select count(1) from t_user where realName like ?</string>
      </entry>
    sql.xml

     在main方法中添加:

    <form id="queryForm">
            <input type="hidden" name="method" value="list" />
            <input type="hidden" name="curPage" value="1" />
            姓名:<input name="realName" />
            <input type="button" value="查询" onclick="sepPage(1)" />
            
    </form>
        <div id="dataDiv">
    main.jsp
    并完善script中定义的function函数seppage:
    <script type="text/javascript">
            //分页函数
            function sepPage(toPage) {
                var JForm = $("form#queryForm");
                //获取name=curPage的输入框中的值
                $("input[name=curPage]:hidden",JForm).val(toPage);
                //序列表表格内容为字符串。
                var queryString = JForm.serialize();
                
                //ajax回调函数
                function callBack(data){
                    $("div#dataDiv").html(data);
                }
                /*
                * A、如果需要get方式提交则可以调$.get(…)
                    B、get与post一共有四个参数:
                    第一个参数:提交的服务端地址
                    第二个参数:提交到服务端的参数
                    第三个参数:服务端成功响应回来之后的回调函数,回调函数的参数表示服务端响应回来的数据
                    第四个参数:服务端响应回来的数据格式(html、json、xml)
                */
                $.post("/BigData6-1/userAction",
                        queryString,
                        callBack,
                        "html")
            }
        </script>
    sepPage函数

     此时sepPage函数调用的是Action的list函数,由于之前都是实用的service层的getUserList函数来进行具体操作,但是之前都是只传递了两个参数(但前页curPage和每页显示的记录数COUNT);要修改起来比较麻烦,所以我们此时选择new一个Map来传参;则:

        public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String curPage = request.getParameter("curPage");//curPage得到的是String类型需转化为integer类型
            String realName = request.getParameter("realName");
            realName = new String(realName.getBytes("ISO-8859-1"), "UTF-8");//需要转码中文才能搞定
            
            Map<String, Object> args = new HashMap<String, Object>();
            args.put("curPage", Integer.parseInt(curPage));
            args.put("count", COUNT);
            if (null != realName && !realName.trim().isEmpty()) {
                args.put("realName", realName);
            }
            
            
            Map<String, Object> resMap = userService.getUserList(args);
    Action中函数list的修改
    public Map<String, Object> getUserList(Map<String, Object> params);
    UserService中getUserList参数修改
        @Override
        public Map<String, Object> getUserList(Map<String, Object> args) {
            //取出分页查询参数
            Integer curPage =  (Integer)args.get("curPage");
            Integer count = (Integer) args.get("count");
            String realName =  (String) args.get("realName");
    
            //计算分页的起始索引
            Integer start = (curPage-1)*count;
            //包装分页字典
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("start", start);
            params.put("count", count);
                    
            
            if (null != realName) {//分页查询显示列表
                params.put("realName", "%"+realName+"%");
            }            
            
            //查询表的总记录数量
            Integer totalCount = userDao.selectUserCount(params);
            //计算总页数
            Integer totalPage = totalCount/count;
            if (totalCount%count != 0) {//如果有余数,则总页数加1
                totalPage++;
            }
            
            //通过分页参数查询分页数据
            List<User> userList = userDao.selectUserList(params);
    UserServiceImple的getUserList函数实现做的修改
        @Override
        public Integer selectUserCount(Map<String, Object> params) {
            Object realName = params.get("realName");
            List<Number> counts = null;
            if (null == realName) {//登陆之后查询表的总数量
                String sql = sqlMap.get("selectUserCount");
                counts = executeDQL(Number.class, sql);//用Number可以避免一切返回类型不兼容问题
            }else { //条件查询总数量
                String sql = sqlMap.get("selectUserCountByCondition");
                counts = executeDQL(Number.class, sql, realName);
            }
            return null!= counts&&!counts.isEmpty()?counts.get(0).intValue():null;
        }
    UserServiceImpl中调用的dao层的selectUserCount的优化
    @Override
        public List<User> selectUserList(Map<String, Object> params) {
            Integer start = (Integer) params.get("start");
            Integer count = (Integer) params.get("count");
            Object realName = params.get("realName");
            
            List<User> userList = null;
            
            if (null == realName) {//登陆之后显示主页列表
                String sql = sqlMap.get("selectUserList");
                userList = executeDQL(User.class, sql, start, count);
            }else { //条件查询加分页显示列表
                String sql = sqlMap.get("selectUserListByCondition");
                userList = executeDQL(User.class, sql, realName, start, count);
            }
            return userList;
        }
    UserServiceImpl中调用的dao层的selectUserList的优化

      进行到此时,测试代码,成功登陆就,同样能够得到用户列表并操作分页功能。

      ==========这是华丽的分割线============

     此时有个用户注册的页面,注册时需要上传头像,保存到数据库,能正确表现出来。
    所以需要写个register.jsp页面;数据传递方式采用json;代码如下
    在这里我犯了一个严重的错误:register.jsp页面中的register函数中的传值部分的dataType属性名写错了,写成dateType;这两个单词很接近,查了好久都没找到,所以单词还是很关键啊。
        <script type="text/javascript">
            //用户注册函数
            function register(Form) {
                var dict = {
                    url:"/BigData6-1/userAction?method=register",
                    type:"post",
                    //dataType:"xml",
                    dataType:"json",
                    beforeSubmit:function(dataDictList, JForm, options){
                        //此函数用于在提交表单之前进行验证,如果此函数返回false
                        //则取消表单的提交
                    },
                    success:function(jsonDict) {
                        //此函数是服务端成功响应回来之后需要回调的函数
                        $("input:button", Form).val("继续注册");
                        //修改图片的路径
                        $("img#userPhoto").attr("src",jsonDict.photoPath);
                        
                        
                        /*
                        //从XML文档中提取图片路径
                        var imgPath =$("body",xmlDoc).html();
                        alert(imgPath);
                        //修改图片的路径
                        $("img#userPhoto").attr("src",imgPath);
                        */
                    }
                    
                }
    
                
                //使用ajax提交带有文件域的表单
                $(Form).ajaxSubmit(dict);
                
                
                
                
            }
        
        
        </script>
    View Code
      1 package com.mmzs.bigdata.action;
      2 
      3 import java.io.File;
      4 import java.io.IOException;
      5 import java.io.PrintWriter;
      6 import java.io.StringWriter;
      7 import java.sql.Date;
      8 import java.util.HashMap;
      9 import java.util.List;
     10 import java.util.Map;
     11 
     12 import javax.jms.ObjectMessage;
     13 import javax.servlet.ServletException;
     14 import javax.servlet.http.HttpServletRequest;
     15 import javax.servlet.http.HttpServletResponse;
     16 
     17 import org.apache.commons.fileupload.FileItem;
     18 import org.codehaus.jackson.map.ObjectMapper;
     19 
     20 import com.mmzs.bigdata.po.User;
     21 import com.mmzs.bigdata.service.UserService;
     22 import com.mmzs.bigdata.service.UserServiceImpl;
     23 import com.thoughtworks.xstream.mapper.Mapper;
     24 
     25 /**
     26  * 用户模块控制器
     27  * @author Administrator
     28  *
     29  */
     30 /**
     31  * @author Administrator
     32  *
     33  */
     34 public class UserAction extends BaseAction {
     35     
     36     private UserService userService;
     37     
     38     public UserAction() {
     39         userService = new UserServiceImpl();
     40     }
     41     /**
     42      * 用户登录
     43      * @param request
     44      * @param response
     45      * @throws IOException 
     46      * @throws ServletException 
     47      */
     48     public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     49         String userName = request.getParameter("userName");
     50         String passWord = request.getParameter("passWord");
     51         
     52         User user = userService.getUser(userName, passWord);
     53         if (null != user) {//登陆成功
     54             request.getSession().setAttribute("loginUser", user);
     55             Map<String, Object> args = new HashMap<String, Object>();
     56             args.put("curPage", 1);
     57             args.put("count", COUNT);
     58             Map<String, Object> resMap = userService.getUserList(args);
     59 
     60             request.setAttribute("curPage", resMap.get("curPage"));
     61             request.setAttribute("totalPage", resMap.get("totalPage"));
     62             request.setAttribute("userList", resMap.get("userList"));
     63             request.getRequestDispatcher("/main.jsp").forward(request, response);
     64             return;//如果你是一个比较有良知的人,加一个return;因为加了执行到此处就结束,否则会往下执行自动结束;理论上加与不加效果相同;
     65         } else {//登录失败
     66             request.setAttribute("loginError", "用户名或密码输入错误");
     67             request.getRequestDispatcher("/login.jsp").forward(request, response);
     68         }
     69     }
     70     
     71     /**
     72      * 列表分页
     73      * @param request
     74      * @param response
     75      * @throws IOException 
     76      * @throws ServletException 
     77      */
     78     public void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     79         String curPage = request.getParameter("curPage");//curPage得到的是String类型需转化为integer类型
     80         String realName = request.getParameter("realName");
     81         realName = new String(realName.getBytes("ISO-8859-1"), "UTF-8");//需要转码中文才能搞定
     82         
     83         Map<String, Object> args = new HashMap<String, Object>();
     84         args.put("curPage", Integer.parseInt(curPage));
     85         args.put("count", COUNT);
     86         if (null != realName && !realName.trim().isEmpty()) {
     87             args.put("realName", realName);
     88         }
     89         
     90         
     91         Map<String, Object> resMap = userService.getUserList(args);
     92         //大公司操作
     93 //        StringWriter writer = new StringWriter();
     94 //        ObjectMapper mapper = new ObjectMapper();
     95 //        mapper.writeValue(writer, resMap);
     96 //        String jsonString = writer.toString();
     97 //        response.getWriter().write(jsonString);
     98         
     99         //小公司操作
    100         request.setAttribute("curPage", resMap.get("curPage"));
    101         request.setAttribute("totalPage", resMap.get("totalPage"));
    102         request.setAttribute("userList", resMap.get("userList"));
    103         //request.getRequestDispatcher("/main.jsp").forward(request, response);
    104         request.getRequestDispatcher("/table.jsp").forward(request, response);
    105     }
    106     
    107     /**
    108      * 用于处理用户注册
    109      * @param request
    110      * @param response
    111      * @throws ServletException
    112      * @throws IOException
    113      */
    114     public void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    115         //解析带有文件域的表单提交请求
    116         Map<String, List<Object>> paramMap = super.parseUpload(request);
    117         
    118         String userName = (String) paramMap.get("userName").get(0);
    119         String passWord = (String) paramMap.get("passWord").get(0);
    120         String realName = (String) paramMap.get("realName").get(0);
    121         String weight = (String) paramMap.get("weight").get(0);
    122         String height = (String) paramMap.get("height").get(0);
    123         String birthday = (String) paramMap.get("birthday").get(0);
    124         
    125         FileItem photo = (FileItem) paramMap.get("photo").get(0);
    126         //获取文件名
    127         String fileName = photo.getName();
    128         //图片在工程中的相对路径
    129         String photoPath = "/BigData6-1/upload/"+fileName;
    130         
    131         System.out.println(userName+":"+realName+":"+birthday);
    132         //利用注册的用户信息创建对象
    133         User user = new User(userName, passWord, realName, Double.parseDouble(weight), Integer.parseInt(height), 
    134                 Date.valueOf(birthday), photoPath);
    135         //添加用户信息到数据库
    136         Integer pk = userService.addUser(user);
    137         System.out.println("主键:"+pk);
    138         
    139         
    140         //将返回Ajax的信息包装成Json字典对象
    141         Map <String, Object> jsonMap = new HashMap<String, Object>(); 
    142         if (null != pk) {
    143             jsonMap.put("addTip", "success");
    144         }else {
    145             jsonMap.put("addTip", "error");
    146         }
    147         
    148         jsonMap.put("photoPath", photoPath);
    149         
    150         StringWriter writer = new StringWriter();
    151         mapper.writeValue(writer,jsonMap);
    152         String json = writer.toString();
    153         
    154         
    155         
    156         //获取文件需要保存的服务端路径
    157         String filePath = this.getServletContext().getRealPath("/upload");
    158         //根据文件服务端的绝对路径创建对象
    159         File fileFullName = new File(filePath+File.separator+fileName);
    160         PrintWriter pw = null;
    161         try {
    162             //存储文件到服务端指定的路径下
    163             photo.write(fileFullName);
    164             System.out.println(photoPath);
    165             //response.setContentType("text/html;charset=UTF-8");//json格式需要这行代码;xml格式不需要这行代码
    166             pw = response.getWriter();
    167             pw.write(json);
    168             System.out.println(pw);
    169             pw.flush();
    170             
    171         } catch (Exception e) {
    172             e.printStackTrace();
    173         }finally{
    174             if (null != pw) {
    175                 pw.close();
    176             }
    177         }
    178     }
    179     
    180 }
    UserAction
     
     
     
     
     
  • 相关阅读:
    哈希表
    c++中的虚函数
    struct并不报错
    c风格的字符串
    动态数组
    常量指针和指针常量
    关于struct和typedef struct
    常量成员函数
    关于free的使用疑惑
    mutable用于修改const成员函数中的成员变量
  • 原文地址:https://www.cnblogs.com/mmzs/p/7877508.html
Copyright © 2020-2023  润新知