大数据——Dao模式、单例模式和前端页面连接数据库实现登录功能

Dao

封装JDBC

上篇博客中说到使用JDBC连接数据库,其中存在几个弊端。
业务代码和数据访问代码耦合:
(1)可读性差
(2)不利于后期修改和维护
(3)不利于代码复用
解决办法:
(1)将相似功能的代码抽取封装成方法,减少代码冗余
(2)因为不同的数据库会有不同的实现,对数据库的操作一般抽取成接口,在以后的开发中可以降低耦合
隔离业务逻辑代码和数据访问代码。
隔离不同数据库的实现。

实现JDBC封装

将所有增删改查操作抽取成接口
定义实体类传输数据
将通用的操作(打开、关闭连接等)封装到工具类
数据库工具类BaseDao:增、删、改、查的通用方法

什么是Dao

Data Access Object(数据存取对象) 
位于业务逻辑和持久化数据之间
实现对持久化数据的访问

Dao模式的组成部分

DAO接口
DAO实现类
实体类
数据库连接和关闭工具类

优势:

隔离了数据访问代码和业务逻辑代码
隔离了不同数据库实现

配置数据库访问参数

新闻信息存储在MySQL数据库中,但在开发和部署时有可能使用不同的数据库,也可能因为客户的需求而更换数据库产品。此时刚才读取新闻信息的做法有何弊端呢?

弊端
数据库发生改变时,要重新修改代码,重新编译和部署
解决
将数据库信息写在配置文件当中,让程序通过读取配置文件来获得这些信息

属性文件

后缀为.properties
数据格式为“键=值”
使用“#”来注释
Java中提供了Properties类来读取配置文件

示例一:Dao模式实现对新闻信息表的增删改查
(1)创建kgcnews数据库,并创建表,插入数据

CREATE DATABASE `kgcnews`; 
USE `kgcnews`;
CREATE TABLE `news_category` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `createDate` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) 

insert  into `news_category`(`id`,`name`,`createDate`) values
 (1,'国内','2016-09-16 14:41:24'),
 (2,'国际','2016-09-16 14:42:58'),
 (3,'娱乐','2016-09-16 14:42:58'),
 (4,'军事','2016-09-16 14:42:58'),
 (5,'财经','2016-09-16 14:42:58'),
 (6,'天气','2016-09-16 14:42:58');

CREATE TABLE `news_comment` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `newsId` bigint(10) DEFAULT NULL COMMENT '评论新闻id',
  `content` varchar(2000) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '评论内容',
  `author` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '评论者',
  `ip` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '评论ip',
  `createDate` datetime DEFAULT NULL COMMENT '发表时间',
  PRIMARY KEY (`id`)
)

CREATE TABLE `news_detail` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `categoryId` bigint(10) DEFAULT NULL COMMENT '新闻类别id',
  `title` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '新闻标题',
  `summary` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '新闻摘要',
  `content` text COLLATE utf8_unicode_ci COMMENT '新闻内容',
  `picPath` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '新闻图片路径',
  `author` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '发表者',
  `createDate` datetime DEFAULT NULL COMMENT '创建时间',
  `modifyDate` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`)
)
insert  into `news_detail`(`id`,`categoryId`,`title`,`summary`,`content`,`picPath`,`author`,`createDate`,`modifyDate`) values 
(1,1,'Java Web开课啦','Java Web课程重磅开课,学员福利','璇女神主讲,课工场倾力出品,Java Web课程开课了,等靠谱的你来报名!','','admin','2016-05-16 14:43:53','2015-05-16 14:43:53'),
(2,1,' 520课工场Java狂欢节','课工场准备了一大波福利:Java大赛、折扣课程,免费线下福利……你准备好了吗?','在这个五月,课工场Java学员突破100万人。为感谢所有学员的支持,我们特将5月20日定为【课工场Java狂欢节】。课工场准备了一大波福利:Java大赛、折扣课程,免费线下福利……你准备好了吗?',NULL,'admin','2016-05-16 14:43:53','2016-05-16 14:43:53');

CREATE TABLE `news_user` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `userName` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户名',
  `password` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '密码',
  `email` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'email',
  `userType` int(5) DEFAULT NULL COMMENT '用户类型  0:管理员 1:普通用户',
  PRIMARY KEY (`id`)
)
insert  into `news_user`(`id`,`userName`,`password`,`email`,`userType`) values 
(1,'admin','admin','admin@kgc.cn',0),
(2,'user','user','user@kgc.cn',1),
(3,'test','test','test@kgc.cn',1);

(2)导入jar包和Tomcat:
hamcrest-core-1.3.jar
junit-4.12.jar
mysql-connector-java-5.1.38.jar
Tomcat 8.5.45

导入jar包及Tomcat相关配置设置:
1.Tomcat目录地址:
D:\1\apache-tomcat-8.5.45
2、在idea中导入jar包:
File->Project Structure->Modules->Dependencies->±>JARs or directories
导入所需要的jar包,点击左下角的Apply
在这里插入图片描述
3、在idea中配置tomcat:
File->Project Structure->Modules->+选择web->apply
点击右下角create artifact->apply
然后回到Modules->选择项目名->选择Dependencies添加依赖->Tomcat8.5.45 ok
4、配置项目Configurations:
run->Edit Configurations->
On update action:当发现更新时的操作 选择Update classes and resources
On frame deactivation:当IDEA 切换时的操作 (比如缩下去、打开网页等) 选择Update classes and resources
选择Deployment->选择+ Artifact ->
在这里插入图片描述
(3)在主目录下创建一个directory文件名称叫:rescoures
在rescourse文件下创建一个File文件名称叫:db.properties
在这里插入图片描述
(4)在db.properties中输入:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.136.30:3306/kgcnews
user=root
pwd=ok

注意:192.136.136.30是你的IP地址,每个人都是不一样的。
3306是接口。
kgcnews是你使用数据库的名称。
user是你的数据库用户名。
ok是你的mysql的登录密码。

(5)在src下创建一个包,名称为util。
在util下创建一个java程序,名称为Prop。

在这里插入图片描述
(6)在Prop.java中输入:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
//配置文件
//为了要修改为修改
public class Prop {
    private static Properties p = new Properties();
    public static String getP(String param){
        try {
            p.load(new FileInputStream("db.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return p.getProperty(param);
    }
//    public static void main(String[] args) {
//        System.out.println(Prop.getP("driver"));
//    }
}

注意:这里db.properties是相对路径,也可以换为绝对路径:“D:/ideashuju/20200821-web/resources/db.properties”
每个人的绝对路径是不一样的,你要根据你的db.properties文件所在路径输入正确的绝对路径。

(7)创建一个包,名称为Dao。
在Dao包下创建一个java程序,名称为NewsDao

在这里插入图片描述
(8)在NewsDao.java中输入:

import cn.kgc.kb09.util.Prop;

import java.sql.*;

public class NewsDao {//加载驱动,获取连接
    private static String driver = Prop.getP("driver");
    private static String url = Prop.getP("url");
    private static String user = Prop.getP("user");
    private static String pwd = Prop.getP("pwd");
    public static Connection getCon(){
        try {
            Class.forName(driver);
            return DriverManager.getConnection(url, user, pwd);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static ResultSet query(String sql, Object... params) {//查询方法
        Connection conn = getCon();
        PreparedStatement pstmt =null;
                ResultSet rs=null;
        try {
             pstmt = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1,params[i]);
            }
            rs= pstmt.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }
    public static int update(String sql,Object...params) {//增删改方法
        Connection con = getCon();
        PreparedStatement pstmt=null;
        try {
            pstmt = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pstmt.setObject(i + 1, params[i]);
            }
            return pstmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }
}

(9)按下Ctrl+Shift+T创建测试,就会出现一个绿色的test包,里面有一个NewsDaoTest的java程序
在这里插入图片描述
(10)在NewsDaoTest.java中输入:

import org.junit.Test;
import java.sql.ResultSet;
import java.sql.SQLException;


public class NewsDaoTest {//查询

    @Test
    public void query() throws SQLException {
        NewsDao newsDao = new NewsDao();
        String sql = "SELECT summary FROM news_detail WHERE id=? OR id=?";
        ResultSet rs = NewsDao.query(sql, 1, 2);
        while (rs.next()) {
            System.out.println(rs.getString("summary"));
        }
    }

    @Test
    public void testInsert() {//增加
        NewsDao newsDao = new NewsDao();
        String sql = "insert into news_detail(id,categoryId,title,summary,content,picPath,author,createDate,modifyDate)values(?,?,?,?,?,?,?,?,?)";
        int a = NewsDao.update(sql, 3, 2, "特朗普下台了", "特朗普在从参议院的联名投诉下滚下台了", "特朗普世界头号恐怖分子", "null", "admin", "2020-08-21 21:10:10", "2020-08-22 08:00:00");
        System.out.println(a>0 ? "增加成功" : "增加失败");
    }
    @Test
    public void  testDelete() {删除
        NewsDao newsDao = new NewsDao();
        String sql = "delete from news_detail where id=?";
        int b = NewsDao.update(sql, 3);
        System.out.println(b>0 ? "删除成功" : "删除失败");
    }

    @Test
    public void testUpdate() {//改
        NewsDao newsDao = new NewsDao();
        String sql = "update news_detail set title=? where id=?";
        int c = NewsDao.update(sql, "大数据开课了,明星老师罗鑫手把手面对面一对一教导,晚上深夜辅导赶紧加入吧,口碑走一波", 1);
        System.out.println(c>0 ? "更改成功" : "更改失败");
    }
}

输入结果:
在这里插入图片描述
注意:我这边在还没有增加之前,就执行了删除的操作,所以会出现删除失败的结果。如果是一步一步执行下来,就不会出现这样的问题。

单例模式

为何需要单例模式

BaseDao:操作数据库的基类
每个线程对系统操作都需new一个BaseDao实例
初始化时的I/O操作消耗系统资源,影响系统性能
对于每个线程,可共享一个实例

什么是单例模式

系统运行期间,有且仅有一个实例
一个类只有一个实例——最基本的要求
只提供私有构造器
它必须自行创建这个实例
定义了静态的该类私有对象
它必须自行向整个系统提供这个实例
提供一个静态的公有方法,返回创建或者获取本身的静态私有对象
在并发环境下上述的单例模式实现是否存在弊端,线程是否安全?是否会出现多个configManager实例?

懒汉模式
饿汉模式

懒汉模式

类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例
特点
线程不安全
延迟加载(lazy loading)
如何解决线程安全问题?
同步(synchronized)

恶汉模式

在类加载的时候,就完成初始化
特点:
线程安全
不具备延迟加载特性

注意:在整个程序运行期间,有且仅有一个实例。
若违背这一点,所设计的类就不是单例类
单例模式懒汉模式饿汉模式
概念在类加载器时不创建实例,采用 延迟加载的方式,在运行调用时创建实例在类加载的时候,就完成初始化
特点类加载速度快,但是运行时获取对象的速度较慢。——时间换空间类加载较慢,但获取对象速度快。——空间换时间
延迟加载(lazy loa ding )具备不具备
线程安全线程不安全线程安全

前端页面连接数据库实现登录功能

实现登录功能:
登录页面(用户名和密码要能传到后台)index.jsp
Servlet接收数据–>数据传递给service–>service经过合法性判断–>调用Dao的查询方法–>Dao查询返回数据给service–>service进过业务逻辑判断–>把结果传回给servlet–>传回给页面
(1)配置web.xml文件
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>cn.kgc.kb09.controller.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login.html</url-pattern>
    </servlet-mapping>
</web-app>

(2)配置初始页面index.jsp
在这里插入图片描述

<%--
  Created by IntelliJ IDEA.
  User: dongsijai
  Date: 2020/8/21
  Time: 10:49
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
</head>
<body>
<h1>欢迎来到吃货联盟</h1>
<form action="login.html" method="get">
    <p><input type="text" name="username"></p>
    <p><input type="password" name="password"></p>
    <p><input type="submit" value="点我登录"></p>
</form>
</body>
</html>

(3)在src文件下创建一个包,名称为controller
在下面再创建一个java程序,名称为LoginServlet

在这里插入图片描述
(4)在LoginServlet.java中输入:

import cn.kgc.kb09.service.LoginService;
import cn.kgc.kb09.service.LoginServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//主要负责前后台交互
public class LoginServlet extends HttpServlet {
    private LoginService service;
    //也需要调用service方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //先获取到前台传回的数据
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(password);
        System.out.println(username);
        service = new LoginServiceImpl();
        boolean canLogin = service.login(username, password);
//        super.doGet(req, resp);
        if (canLogin) {//可以登陆
            req.setAttribute("rst","恭喜"+username+",登录成功!");
        } else {//不可以登录
            req.setAttribute("rst", "对不起,输入有误,登录不成功!");
        }
        //转发请求到新的页面
        req.getRequestDispatcher("result.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.service(req, resp);
    }
}

(5)在src文件下创建一个包,名称为service
在下面再创建一个接口,名称为LoginService
再创建一个java程序实现类,名称为LoginServicelmpl

在这里插入图片描述
(6)在接口LoginService中输入:

public interface LoginService {
    boolean login(String  username, String password);
}

(7)在实现类LoginServicelmpl.java中输入:

import cn.kgc.kb09.dao.LoginDao;
import cn.kgc.kb09.dao.LoginDaoImpl;
import cn.kgc.kb09.entity.User;
import com.mysql.jdbc.StringUtils;

//主要负责业务逻辑判断
public class LoginServiceImpl implements LoginService {
    LoginDao dao;
    @Override
    public boolean login(String username, String password) {
        dao = new LoginDaoImpl();
        //合法性判断
        if (username == null || password == null || username.trim().equals("")
                || password.trim().equals("")) {
            return false;
        }
        //调用dao层的数据查询
        User user = dao.queryUserByNameAndPwd(username, password);
        //如果有返回的数据,则可以登录,否则不可以直接登录
        if (user != null) {
            return true;

        }
        return false;
    }
}

(8)在src文件下创建一个包,名称为Dao
在下面再创建一个接口,名称为LoginDao
再创建一个java程序实现类,名称为LoginDaolmpl
再创建一个java程序,名称为PstDao

在这里插入图片描述

(9)在接口LoginDao中输入:

// An highlighted block
import cn.kgc.kb09.entity.User;
public interface LoginDao {
    User queryUserByNameAndPwd(String username, String password);
}

(10)在实现类LoginDaolmpl.java中输入:

import cn.kgc.kb09.entity.User;

import java.sql.ResultSet;
import java.sql.SQLException;

public class LoginDaoImpl  implements LoginDao {
    @Override
    public User queryUserByNameAndPwd(String username, String password) {
        String sql = "select * from user_info where uname=? and password=?";
        ResultSet rs = PstDao.query(sql, username, password);
        User user=null;
        try {
            if (rs.next()) {
                user = new User();
                user.setUsername(rs.getString("uname"));
                user.setPassword(rs.getString("password"));
            }

        }catch (SQLException e){
            e.printStackTrace();
        }
        return user;
    }
}

(11)在PstDao实现连接数据库查询,输入:

import cn.kgc.kb09.util.Prop;
import java.sql.*;
import java.time.Period;
public class PstDao {
    private static String driver= Prop.getP("driver");
    private static String url = Prop.getP("url");
    private  static String user=Prop.getP("user");
    private static String pwd=Prop.getP("pwd");
    public static Connection getConn(){
        try {
            Class.forName(driver);
           return DriverManager.getConnection(url, user, pwd);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void close(Connection conn, PreparedStatement pst, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pst != null) {
            try {
                pst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static ResultSet query(String sql,Object... params) {
        Connection conn = getConn();
        PreparedStatement pst=null;
        ResultSet rs=null;
        try {
            pst = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i + 1, params[i]);
            }
            rs=pst.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }

    public static int update(String sql, Object... params) {
        Connection conn = getConn();
        PreparedStatement pst=null;
        try {
            pst = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                pst.setObject(i + 1, params[i]);
            }
            return pst.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if (pst != null) {
                try {
                    pst.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }
}

(12)重新配置db.properties,输入:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.136.30:3306/userControl
user=root
pwd=ok

(13)重新配置Prop.java,输入:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
//配置文件
//为了要修改为修改
public class Prop {
    private static Properties p = new Properties();
    public static String getP(String param){
        try {
            p.load(new FileInputStream("D:/ideashuju/20200821-web/resources/db.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return p.getProperty(param);
    }

注意:在Java Web项目中要使用绝对路径。
(14)在src文件在下创建一个包,名称为entity,
在下面创建一个java程序,名称为User

在这里插入图片描述
(15)在User.java中输入:

//实体类
public class User {
    private String username;
    private String password;

    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;
    }
}

(16)在跟index.jsp同级目录下创建一个result.jsp,输入:

<%--
  Created by IntelliJ IDEA.
  User: dongsijai
  Date: 2020/8/22
  Time: 11:47
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录结果页面</title>
</head>
<body>
<%
   Object rst = request.getAttribute("rst");
%>
<h1><%=rst%></h1>
</body>
</html>

(17)右击index.jsp,选择run执行这个程序,就会自动跳转出来一个界面
在这里插入图片描述
(18)输入用户名和密码,点击点我登录
在这里插入图片描述
到这一步,才是完整的实现了页面的登录。

  • 3
    点赞
  • 8
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

蜂蜜柚子加苦茶

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值