Java EE_实现在服务器上登录,并将登录信息存储到数据库中

一、配置文件

  1. IDEA
  2. Mysql8.0 和 SQLyog
  3. Tomcat服务器
  4. jar包:
    commons-logging-1.2.jar
    druid-1.1.22.jar
    mysql-connector-java-8.0.21.jar
    spring-beans-5.1.10.RELEASE.jar
    spring-core-5.1.10.RELEASE.jar
    spring-jdbc-5.1.10.RELEASE.jar
    spring-tx-5.1.10.RELEASE.jar
  5. 自定义的配置文件:druid.properties
url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=GMT%2B8
username=root
password=root
driverClassName=com.mysql.cj.jdbc.Driver
#最初连接数
initialSize=10
#最大连接数
maxActive=20
#最多等待时间
maxWait=1000
filters=wall
#是否开启超时自动回收连接
spring.datasource.removeAbandoned=true
#设置自动回收连接的超时时间
spring.datasource.removeAbandonedTimeout=180
#打印回收连接时的错误日志
spring.datasource.logAbandoned=true
  1. 登录界面login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/request/Servlet_demo1" method="post">
          账号:<input type="text" name="username"> <br>
          密码:<input type="password" name="password"><br>

        <input type="submit" value="登录">

    </form>
</body>
</html>

二、工具类

  1. informationadd :javabean类,用来set和get用户信息
public class informationadd {

    private int id;//手机号
    private String username;//昵称
    private String sex;//性别
    private String date;//出生日期
    private String password;//密码

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "informationadd{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", date='" + date + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
  1. Util_Druid:加载druid.properties配置文件和得到数据库连接池对象
public class Util_Druid {
    private static DataSource ds ;

    static {
        try {
            //1.创建配置文件对象
            Properties pro = new Properties();
            //2.加载配置文件
            InputStream in = Util_Druid.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(in);
            //3.创建DataSource 连接池
            ds = DruidDataSourceFactory.createDataSource(pro);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //4.创建连接对象
    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
    //返回DateSource连接池对象
    public static DataSource getDataSource(){
        return ds;
    }

    //5.释放资源
    public static void close(ResultSet result, Statement state , Connection conn){
        if (result != null){
            try {
                result.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (state != null){
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

  1. Database_method:操作数据库连接池对象,SetUser判断数据库是否存在账号,存入封装类,InsertUser在封装类中取出信息添加到数据库中
public class Database_method {

    //封装类 存放的是用户信息
    private informationadd informat = new informationadd();
    //JdbcTemplate 操作数据库连接池对象
    private JdbcTemplate temp = new JdbcTemplate(Util_Druid.getDataSource());

//    public static void main(String[] args) {
//        Database_method method = new Database_method();
//        int i = method.SetUser(4,"22","男","44","11");
//        int j = 0;
//        if (i==1){//得到返回值i为1的话就存到数据库
//            j = method.InsertUser();
//            System.out.println("存入封装类成功...");
//        }else System.out.println("存在此手机号,存入封装类失败...");
//
//        if (j==1){
//            System.out.println("存入数据库成功...");
//        }else System.out.println("存入数据库失败...");
//    }

    //先将用户的信息存储到封装类里,返回0就是没存入封装类里,返回1就是存到了封装类
    public int SetUser(int id,String username,String sex ,String date,String password){
        //如果id不空
        if (id != 0){
            //查询数据库中有没有相同的手机号,
           String sql = "select count(*) from userhelp where id = ? ";
           //返回查询到的行数,如果有就是count=1
           int count = temp.queryForObject(sql,int.class,id);
           if (count == 0){//count=0说明没有查询到,也就是没此手机号,可以新建
               informat.setId(id);//手机号放入封装类
               System.out.println("没有此手机号,可以存入封装类");
               if (username != null && sex != null && date != null) {
                   informat.setUsername(username);//将昵称放入封装类中
                   informat.setSex(sex);//将性别放入封装类
                   informat.setDate(date);//将日期放入类中
                   informat.setPassword(password);//将密码放入类中
                   return 1;
               }else {
                   System.out.println("昵称、性别或者日期 存在空值");
                   return 0;
               }
           }
        }
        //判断第一次输入密码和第二次输入密码是否相同,这个在客户端完成就可以
        return 0;
    }

    //将设置好的封装类加入数据库表中,返回执行条数若是为0就是没存入数据库,返回1就是加入成功了
    public int InsertUser(){
        String sql = "insert  into userhelp(id,username,sex,date,password) value(?,?,?,?,?)";
        int update = temp.update(sql, informat.getId(), informat.getUsername(), informat.getSex(), informat.getDate(), informat.getPassword());
        return update;
    }
}

四、HttpServlet类

接收到服务器页面的消息参数,调用上面Database_method类的两个方法将消息参数存储到数据库,并且判断成功与否。

@WebServlet("/Servlet_demo1")
public class Servlet_demo1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置参数编码
        request.setCharacterEncoding("utf-8");

        //获得参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("账号:"+username+"--"+"密码:"+password);
        int ss=0;
        try
        {
            ss = Integer.parseInt(username);
        }catch (Exception e){
            System.out.println("您输入的账号不是数字,数据库存储失败");
            System.out.println("-----------分隔符--------------");
            return;
        }

        Database_method method = new Database_method();
        int i = method.SetUser(ss,"22","男","44",password);
        int j = 0;
        if (i==1){//得到返回值i为1的话就存到数据库
            j = method.InsertUser();
            System.out.println("存入封装类成功...");
        }else {
            System.out.println("存在此账号,存入封装类失败...");
        }

        if (j==1){
            System.out.println("存入数据库成功...");
            System.out.println("-----------分隔符--------------");
        }else {
            System.out.println("存入数据库失败...");
            System.out.println("-----------分隔符--------------");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

五、运行结果

我尝试了三组数据,第一第二组完全一样,第三组我把账号故意写成字符类型,下面的运行结果皆正常。

1.界面

在这里插入图片描述
2.控制台和数据库页面

在这里插入图片描述
六、遇到的BUG

1.如图HTTP页面报错状态500
在这里插入图片描述
原因和解决办法请看我的另外一篇文章:上图中的问题产生原因和解决办法

  1. 目前位置还有一个问题没解决,在我关闭服务器之后报错
26-Aug-2020 18:14:14.179 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [request] 注册了JDBC驱动程序 [com.alibaba.druid.proxy.DruidDriver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
26-Aug-2020 18:14:14.179 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc Web应用程序 [request] 注册了JDBC驱动程序 [com.mysql.cj.jdbc.Driver],但在Web应用程序停止时无法注销它。 为防止内存泄漏,JDBC驱动程序已被强制取消注册。
26-Aug-2020 18:14:14.180 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[request]似乎启动了一个名为[mysql-cj-abandoned-connection-cleanup]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 java.lang.Object.wait(Native Method)
 java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
 com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:85)
 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 java.lang.Thread.run(Thread.java:748)]
26-Aug-2020 18:14:14.180 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[request]似乎启动了一个名为[Druid-ConnectionPool-Create-1627339834]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2754)]
26-Aug-2020 18:14:14.181 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[request]似乎启动了一个名为[Druid-ConnectionPool-Destroy-1627339834]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 java.lang.Thread.sleep(Native Method)
 com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:2850)]
26-Aug-2020 18:14:14.182 严重 [main] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks web应用程序[request]创建了一个ThreadLocal,其键类型为[java.lang.ThreadLocal](值为[java.lang.ThreadLocal@319b92f3]),值类型为[com.alibaba.druid.wall.spi.WallVisitorUtils.WallTopStatementContext](值为[com.alibaba.druid.wall.spi.WallVisitorUtils$WallTopStatementContext@fcd6521),但在停止web应用程序时未能将其删除。线程将随着时间的推移而更新,以尝试避免可能的内存泄漏
26-Aug-2020 18:14:14.192 信息 [main] org.apache.coyote.AbstractProtocol.stop 正在停止ProtocolHandler ["http-nio-8080"]
26-Aug-2020 18:14:14.194 信息 [main] org.apache.coyote.AbstractProtocol.destroy 正在摧毁协议处理器 ["http-nio-8080"]

从上面报错来看,我感觉是我用了Druid的连接池产生的问题,但是木有关闭它的办法,所以访问一次页面就会新建一个连接池,每个连接池又会新建10个连接对象,然后我手动关闭服务器这些对象得不到释放,导致多个线程tomcat也不能正常关闭,这样就有可能内存泄露,只能强制关闭,然后飘红报错。

经过我一顿搜索终于手动关闭了Driver注册和闲置检测:Daemon Thread [Abandoned connection cleanup thread] ,是用的以下代码,是我写了一个监听器。

public class MyContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("webService start");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("webService stop");
        try {
            //手动取消jdbc程序的注册
            while(DriverManager.getDrivers().hasMoreElements()) {
                DriverManager.deregisterDriver(DriverManager.getDrivers().nextElement());
            }
            System.out.println("jdbc Driver close");
            //手动停止名为[mysql-cj-abandoned-connection-cleanup]的线程
            AbandonedConnectionCleanupThread.uncheckedShutdown();
            System.out.println("clean thread success");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

还有要在web.xml添加

    <!--监听侦-->
    <listener>
        <listener-class>cn.web.servlet.MyContextListener</listener-class>
    </listener>

但是还有如下错误:

26-Aug-2020 20:42:20.636 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[request]似乎启动了一个名为[Druid-ConnectionPool-Create-2099465138]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
 com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2754)]
26-Aug-2020 20:42:20.637 警告 [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[request]似乎启动了一个名为[Druid-ConnectionPool-Destroy-2099465138]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
 java.lang.Thread.sleep(Native Method)
 com.alibaba.druid.pool.DruidDataSource$DestroyConnectionThread.run(DruidDataSource.java:2850)]
26-Aug-2020 20:42:20.638 严重 [main] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks web应用程序[request]创建了一个ThreadLocal,其键类型为[java.lang.ThreadLocal](值为[java.lang.ThreadLocal@103f852]),值类型为[com.alibaba.druid.wall.spi.WallVisitorUtils.WallTopStatementContext](值为[com.alibaba.druid.wall.spi.WallVisitorUtils$WallTopStatementContext@587c290d),但在停止web应用程序时未能将其删除。线程将随着时间的推移而更新,以尝试避免可能的内存泄漏
26-Aug-2020 20:42:20.648 信息 [main] org.apache.coyote.AbstractProtocol.stop 正在停止ProtocolHandler ["http-nio-8080"]
26-Aug-2020 20:42:20.650 信息 [main] org.apache.coyote.AbstractProtocol.destroy 正在摧毁协议处理器 ["http-nio-8080"]
Disconnected from server

从上边报错看出来也就是下面这三个线程没关,但。。我不会关闭。。。。。。。

创建连接:Daemon Thread [Druid-ConnectionPool-Create-1184124073]
废弃连接:Daemon Thread [Druid-ConnectionPool-Destroy-1184124073]
web应用程序[request]创建了一个ThreadLocal

各位路过的大佬有没有关闭这几个线程的办法?


版权声明:本文为kaikai_gege原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。