简单登录案例
工作配置:
操作系统:windos10
jdk版本:jdk1.8
mysql版本:8.0.22
Tomcat版本:9.0.414
1.案例分析
功能分析:输入账号 密码,若输入的信息正确,则跳转到输入正确的页面,若输入的信息不正确则跳转到输入不正确的页面
功能实现思路:
1.输入账号和密码使用HTML中的form表单实现,使用JSP页面完成。
2.判断输入的信息是否正确则使用数据库来完成,通过输入的信息在数据库中查找相应的值,若可以查找则返回用户信息,若查找不到则返回NULL,以此来怕判断信息是否正确
3.页面跳转用Servlet中的request.getRequestDispatcher(xxx).forward,(转发)完成。
2.相关知识点
因为做这次登录案例,我也是参考视频做的,其中学了很多新的知识点比如数据库连接池、Spring框架下的Template操作数据库、BeanUtils类的封装数据的使用等等知识,所以我现在这里记录一下。
1.数据库连接池
概念:其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
2. 好处:
1. 节约资源
2. 用户访问高效
3. 实现:
1. 标准接口:DataSource javax.sql包下的
1. 方法:
* 获取连接:getConnection()
* 归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接
2. 一般我们不去实现它,有数据库厂商来实现
1. C3P0:数据库连接池技术
2. Druid:数据库连接池实现技术,由阿里巴巴提供的
Druid数据库连接池实现技术
1. 步骤:
1. 导入jar包 druid-1.0.9.jar
2. 定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下
3. 加载配置文件。Properties
4. 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
5. 获取连接:getConnection
* 代码:
//3.加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//4.获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//5.获取连接
Connection conn = ds.getConnection();
2. 定义工具类
1. 定义一个类 JDBCUtils
2. 提供静态代码块加载配置文件,初始化连接池对象
3. 提供方法
1. 获取连接方法:通过数据库连接池获取连接
2. 释放资源
3. 获取连接池的方法
* 代码:
public class JDBCUtils {
//1.定义成员变量 DataSource
private static DataSource ds ;
static{
try {
//1.加载配置文件
Properties pro = new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 释放资源
*/
public static void close(Statement stmt,Connection conn){
/* if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();//归还连接
} catch (SQLException e) {
e.printStackTrace();
}
}*/
close(null,stmt,conn);
}
public static void close(ResultSet rs , Statement stmt, Connection conn){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();//归还连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 获取连接池方法
*/
public static DataSource getDataSource(){
return ds;
}
}
Spring JDBCTemplate
* Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
* 步骤:
1. 导入jar包
2. 创建JdbcTemplate对象。依赖于数据源DataSource
* JdbcTemplate template = new JdbcTemplate(ds);
3. 调用JdbcTemplate的方法来完成CRUD的操作
* update():执行DML语句。增、删、改语句
* queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
* 注意:这个方法查询的结果集长度只能是1
* queryForList():查询结果将结果集封装为list集合
* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
* query():查询结果,将结果封装为JavaBean对象
* query的参数:RowMapper
* 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
* new BeanPropertyRowMapper<类型>(类型.class)
* queryForObject:查询结果,将结果封装为对象
* 一般用于聚合函数的查询
BeanUtils工具类,简化数据封装
* 用于封装JavaBean的
1. JavaBean:标准的Java类
1. 要求:
1. 类必须被public修饰
2. 必须提供空参的构造器
3. 成员变量必须使用private修饰
4. 提供公共setter和getter方法
2. 功能:封装数据
2. 概念:
成员变量:
属性:setter和getter方法截取后的产物
例如:getUsername() --> Username--> username
3. 方法:
1. setProperty()
2. getProperty()
3. populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
以上笔记都是看视频中借鉴老师的,主要自己表达不了更好就就复制粘贴了,主要是为了记录自己的学习笔记和过程,不是为了收益。如果有侵权我会及时删除的。
首先我们为了让整个逻辑结构清晰可观,就需要使用到MVC设置模式
何谓MVC设计模式呢?
1)显示层(View)
代表用户交互界面,在Web应用中,可以是JSP、HTML、CSS、JavaScrip程序。使用MVC模式设计的视图层仅仅进行数据的采集和处理,以及用户的请求,而业务流程的控制和处理则是交给控制层(Controller)和模型层(Model)。
(2)模型层(Model)
模型层更多是Java编写的,它接受视图层请求的数据,然后进行相应的业务处理,并返回最终的处理结果。模型层担负的责任最为核心,并使得应用程序得到重用和可扩展。
(3)控制层(Controller)
控制层是从用户端接收请求,将模型和视图匹配在一起,共同完成用户地请求。它的作用就是告诉容器应该选择什么样的视图以及选择什么样的模型。例如,当一个用户点击一个链接时,控制层接受到请求之后,并不直接进行任何的数据操作,而是把用户的请求信息传递给相应的模型层,并告诉模型应该进行什么样的操作,最后根据操作结果选择符合要求的视图返回给请求用户。
控制器在MVC设计模式中就是一个中间枢纽的作用,协调着视图和模型层的操作。
MVC设计模式的优点(网上借鉴的):
1.低耦合性
视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码,同样,一个应用的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。
2.高重用性和可适用性
随着技术的不断进步,现在需要用越来越多的方式来访问应用程序。MVC模式允许你使用各种不同样式的视图来访问同一个服务器端的代码。它包括任何 WEB(HTTP)浏览器或者无线浏览器(wap),比如,用户可以通过电脑也可通过手机来订购某样产品,虽然订购的方式不一样,但处理订购产品的方式是 一样的。由于模型返回的数据没有进行格式化,所以同样的构件能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这 些表示所需要的命令是改变视图层的实现方式,而控制层和模型层无需做任何改变。
3.较低的生命周期成本
MVC使开发和维护用户接口的技术含量降低。
4.快速的部署
使用MVC模式使开发时间得到相当大的缩减,它使程序员(Java开发人员)集中精力于业务逻辑,界面程序员(HTML和JSP开发人员)集中精力于表现形式上。
5.可维护性
分离视图层和业务逻辑层也使得WEB应用更易于维护和修改。
6.有利于软件工程化管理
由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化管理程序代码。
3.代码实现过程
首先是View层,因为这次的案例比较简单,所以View层也相对简单一点
1.JSP页面的代码实现
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录界面</title>
</head>
<body>
<form action="/Login/LoginServlet" method="post">
用户名:<input type="text" name="username" placeholder="请输入用户名">
<br>
密码:<input type="password" name="password" placeholder="请输入密码">
<br>
<input type="submit" name="提交">
</form>
</body>
</html>
然后是model层,编写程序应有的功能(实现算法等等)、进行数据管理和数据库设计(可以实现具体的功能),一般Dao层(一般用于操作数据库)和一些封装数据的类还有数据库的连接操作(JDBCUtils类)就是属于model层的
工具类
JDBCUtils类
druid.properties内容:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql:///login?&serverTimezone=UTC
username=root
password=
initialSize=5
maxActive=10
maxWait=3000
package cn.itcast.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtil {
private static DataSource ds;
static {//这一步的作用是导入properties文件
Properties pro = new Properties();
InputStream is = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
//这一步的目的是获取druid.properties路径以及信息
//druid.propertis是自己创建的一个properties文件,里面的内容是连接数据库所要的参数
try {
pro.load(is);//加载文件内容到pro对象中
} catch (IOException e) {
e.printStackTrace();
}
try {
ds = DruidDataSourceFactory.createDataSource(pro);
//这一步就是利用druid工厂帮我们完成连接,我们只需要提供连接参数即可。
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void close(PreparedStatement stmt, Connection con) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (con != null) {
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static DataSource getDs() {
return ds;
}
}
封装数据的User类
package cn.itcast.domain;
public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String name, String password) {
this.id = id;
this.username = name;
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + 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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
操作数据库的UserDao层
package cn.itcast.dao;
import cn.itcast.domain.User;
import cn.itcast.util.JDBCUtil;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
public class UserDao {//Dao类用于操作数据库
//声明template对象,以便操作数据库
private JdbcTemplate template = new JdbcTemplate(JDBCUtil.getDs());
//登录方法
public User login(User loginUser) {
String sql = "select * from user where username = ? and password = ?";
User user;
try {
user = template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(),
loginUser.getPassword());
//BeanPropertyRowMapper,用于封装数据到User中
} catch (EmptyResultDataAccessException e) {
//这里的作用是如果在数据库中找不到我们输入的数据就返回null,否则就不会进行页面跳转
return null;
}
return user;
}
}
数据库的设计
这个数据库很简答,不多说
注意:id为主键,且不为空
最后是Controller层,Controller(控制器):负责转发请求,对请求进行处理。所以Controller一般就是指Servlet里的内容
LoginServlet:处理JSP提交的信息
package cn.itcast.servlet;
import cn.itcast.dao.UserDao;
import cn.itcast.domain.User;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码
req.setCharacterEncoding("utf-8");
/* 封装数据
User loginUser = new User();
loginUser.setUsername(req.getParameter("username"));
loginUser.setPassword(req.getParameter("password"));
//操作数据库,查找是否存在用户
UserDao userdao = new UserDao();
User user = userdao.login(loginUser);*/
//使用BeanUtils类
//1.用Map集合获取所有参数
Map<String,String[]> map = req.getParameterMap();
//2.创建User对象
User loginUser = new User();
//3.使用BeanUtil
try {
BeanUtils.populate(loginUser,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
UserDao userdao = new UserDao();
User user = userdao.login(loginUser);
if (user == null){
//登陆失败
req.getRequestDispatcher("/failLogin").forward(req,resp);
}else {
//登录成功
//存储数据
req.setAttribute("user",user);
//转发到页面
req.getRequestDispatcher("/successLogin").forward(req,resp);
}
}
}
FailLoginServlet:登录失败跳转的页面
package cn.itcast.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/failLogin")
public class FailLoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("登录失败,用户名或者密码错误");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
SuccessLoginServlet:登录成功跳转的页面
package cn.itcast.servlet;
import cn.itcast.domain.User;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/successLogin")
public class SuccessLoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
User user = (User) request.getAttribute("user");//获取提交User的信息,封装到新的User对象中
if (user != null) {//保险起见再判断一次
response.getWriter().write("登录成功," + user.getUsername() + ",欢迎您");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
结果展示:
输入正确:
输入错误
感想
这次的简单的案例花费了我很多时间,主要花在了学习数据库连接池和template的使用上,这些看似很简单的功能,代码是实现起来却不容易,学习编程是一件不容易的事情,需要不断地学习和实践才能达到一定水平。