1.创建数据库
-- 创建数据库,并指定默认字符集和校对规则
CREATE DATABASE IF NOT EXISTS day14 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 使用数据库
USE day14;
-- 创建用户表,并使用utf8mb4字符集
CREATE TABLE IF NOT EXISTS user (
id INT AUTO_INCREMENT PRIMARY KEY,
USERNAME VARCHAR(50) NOT NULL,
PASSWORD VARCHAR(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 插入数据,中文字符可以直接插入
INSERT INTO user (USERNAME, PASSWORD) VALUES ('张策', '123456');
INSERT INTO user (USERNAME, PASSWORD) VALUES ('老王', '654321');
2.导入jar包,添加为库
所需jar包网盘分享啦
链接: https://pan.baidu.com/s/19bbnYveartZ14BokzwVuTQ?pwd=zc66 提取码: zc66 复制这段内容后打开百度网盘手机App,操作更方便哦
3.代码实现
druid.properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day14?useUnicode=true&characterEncoding=utf-8
username= 数据库用户名默认root
password=数据库密码
initialSize= 5
maxActive=10
maxWait=3000
(注意day14是前面数据库建立的名称useUnicode=true&characterEncoding=utf-8是设置了jdbc和数据库连接时的编码形式可实现中文数据对接)
lonjin.jsp
思路及代码解释
1.这段代码告诉服务器如何处理这个页面的内容,即使用UTF-8编码方式处理text/html格式的内容,并且使用Java语言编写脚本。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2.建立表单提交到LoginServlet中
3.如果错误了就打印对应的字符,对应的字符在LoginServlet中设置,并且使用三目运算符如果没设置错误信息即没有错误时为空字符""
<div><%=request.getAttribute("c_error")==null?"":request.getAttribute("c_error")%></div>
<div><%=request.getAttribute("login_error")==null?"":request.getAttribute("login_error")%></div>
4.验证码的图片来自CheckCodeServlet中
同时设置点击事件,每次点击将CheckCodeServlet后面用?传一个时间戳(时间戳的意义是时间永远不重复所以每次都不一样实现了反复申请新的验证码)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>longin</title>
<script>
window.onload=function(){
document.getElementById("img").onclick=function(){
this.src="CheckCodeServlet?"+new Date().getTime();
}
}
</script>
<style>
div{
color:red;
}
</style>
</head>
<body>
<form action="LoginServlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>验证码:</td>
<td><input type="text" name="checkCode"></td>
</tr>
<tr>
<td colspan="2"><img id="img"src="CheckCodeServlet" alt="验证码"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"></td>
</tr>
</table>
<div><%=request.getAttribute("c_error")==null?"":request.getAttribute("c_error")%></div>
<div><%=request.getAttribute("login_error")==null?"":request.getAttribute("login_error")%></div>
</form>
</body>
</html>
LoginServlet
处理了前端登录页面的请求,包括用户输入数据的获取、验证码的验证以及用户登录是否正确的跳转
package cn.zc.web;
import cn.zc.dao.UserDao;
import cn.zc.domain.User;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置请求和响应的编码格式
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//2.获取请求参数
String username=request.getParameter("username");
String password=request.getParameter("password");
String checkCode = request.getParameter("checkCode");
//先判断验证码是否正确
String sessionId=(String) request.getSession().getAttribute("captchaCode");
//忽略大小写
User user = new User();
user.setUsername(username);
user.setPassword(password);
if(checkCode.equalsIgnoreCase(sessionId)){
UserDao dao = new UserDao();
User loginuser = dao.login(user);
request.setAttribute("username",username);
/**
* 注意
* request.getRequestDispatcher("/longin.jsp").forward(request,response);
* response.sendRedirect(request.getContextPath()+"/success.jsp");
* 这两行代码的区别是什么?
* 第一个是在本页跳转,在服务器内部完成跳转,客户端不会察觉到请求的转发,因为浏览器只会显示最终被转发的页面的内容。
* 地址栏不会变
* 第二个是在服务器内部进行重定向,客户端会察觉到请求的转发,会向新的URL发送请求,服务器会根据新的URL进行处理。
* 地址栏会发生变化
*/
if(loginuser==null){
request.setAttribute("login_error","用户名或密码错误");
request.getRequestDispatcher("/longin.jsp").forward(request,response);
}else {
request.getSession().setAttribute("user",username);
response.sendRedirect(request.getContextPath()+"/success.jsp");
}
}else {
//验证码错误
request.setAttribute("c_error","验证码错误");
request.getRequestDispatcher("/longin.jsp").forward(request,response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
CheckCodeServlet生成验证码
思路:
1.获取用户输入的信息
2.先判断验证码是否正确如果不正确就直接设置一个错误信息进入会话,并且再次跳转到登录页面,
这样不需要和数据库进行用户名即密码的判断,提升效率
3.如果验证码正确,将用户输入的数据设置成User对象,传到login的方法中,会返回数据库中这个对象的所有数据
但是如果为空,就说明查不到这个用户,就添加错误信息到对话中并且再次跳转到登录页面
package cn.zc.web;
import javax.imageio.ImageIO;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
/**
* 用于生成验证码图片的Servlet
*/
@WebServlet("/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final int WIDTH = 120; // 图片宽度
private static final int HEIGHT = 40; // 图片高度
private static final int CODE_LENGTH = 4; // 验证码长度
/**
* 处理 GET 请求
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应类型为图像类型
response.setContentType("image/jpeg");
// 创建指定宽度和高度,类型为TYPE_INT_RGB的BufferedImage对象
/**
* BufferedImage.TYPE_INT_RGB 表示创建一个不透明的图像,使用整数像素来
* 存储图像的RGB颜色值,没有Alpha通道,即图像不包含透明度信息。
*/
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// 获取图像的绘图上下文
Graphics graphics = image.getGraphics();
// 设置背景颜色为白色
graphics.setColor(Color.WHITE);
// 填充整个图片区域作为背景
graphics.fillRect(0, 0, WIDTH, HEIGHT);
// 设置边框颜色为黑色
graphics.setColor(Color.BLACK);
// 绘制边框
graphics.drawRect(0, 0, WIDTH - 1, HEIGHT - 1);
// 所有可能的验证码字符
String code = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
StringBuilder captchaCode = new StringBuilder();
Random random = new Random();
// 生成指定长度的随机验证码字符串
for (int i = 0; i < CODE_LENGTH; i++) {
char c = code.charAt(random.nextInt(code.length()));
captchaCode.append(c);
}
// 将生成的验证码字符串存储到用户的会话中
request.getSession().setAttribute("captchaCode", captchaCode.toString());
// 设置文字颜色为黑色,字体样式,绘制生成的验证码文字
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("Arial", Font.BOLD, 20));
/*
* new Font("Arial", Font.BOLD, 20) 创建了一个名为"Arial"的字体,粗体,大小为20。
* 这意味着后续绘制的文本将会使用"Arial"字体,粗体,大小为20。
* */
graphics.drawString(captchaCode.toString(), 40, 25);
// 绘制5条随机干扰线
for (int i = 0; i < 5; i++) {
int x1 = random.nextInt(WIDTH);
int y1 = random.nextInt(HEIGHT);
int x2 = random.nextInt(WIDTH);
int y2 = random.nextInt(HEIGHT);
graphics.drawLine(x1, y1, x2, y2);
}
// 获取响应的输出流,将绘制后的图像以JPEG格式输出到客户端
OutputStream outputStream = response.getOutputStream();
ImageIO.write(image, "jpeg", outputStream);
/*
* 在ImageIO.write方法中,第二个参数"jpeg"表示将图像写入输出流时使用的图像格式,
* 即JPEG格式。这保证图像以JPEG格式进行编码,以便于输出到客户端,并且客户端能够正确解析
* 和显示这个图像。JPEG是一种常见的图像格式,适合用于存储彩色或灰度图像,并且可以通过压缩
* 技术减小图像文件的大小,适合在网络上传输和展示。
* */
outputStream.close();
}
/**
* 处理 POST 请求,重定向到 doGet 方法
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录成功</title>
</head>
<body>
<h1>登录成功</h1>
<p>欢迎您,<%=request.getSession().getAttribute("user")%>!</p><!-- 获取会话中的user属性 -->
</body>
</html>
JdbcUtils
public class JDBCUtils {
private static DataSource ds;
static{
try {
// 创建一个新的 Properties 对象
Properties pro=new Properties();
//通过类加载器获取名为 "druid.properties" 的配置文件的输入流
InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
// 从输入流中加载配置文件的内容到 Properties 对象中
pro.load(inputStream);
// 使用加载了配置文件内容的 Properties 对象创建一个 Druid 数据源对象
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (Exception e) {
e.printStackTrace();//
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static DataSource getDataSource() {
return ds;
}
}
User
package cn.zc.domain;
public class User {
private int id;
private String username;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", UserName='" + username + '\'' +
", PassWord='" + password + '\'' +
'}';
}
}
UserDao
package cn.zc.dao;
import cn.zc.domain.User;
import cn.zc.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
//操作数据库的类
public class UserDao {
/**
* 登录方法
* 传进来的User loginUser是用户登录的User根据这个对象的名字和密码如果能在数据库中查到就
* 通过new BeanPropertyRowMapper<User>(User.class),将数据库的数据映射到Java的User类中
* 闯进一个对象,最后返回,如果没查到就返回空
*
*/
private JdbcTemplate jdbcTemplate=new JdbcTemplate(JDBCUtils.getDataSource());
/**
* JdbcTemplate是Spring框架提供的用于简化JDBC操作的
* 类,它包含了多种执行数据库操作的方法。
*/
public User login(User loginUser){
try {
String sql="select * from user where USERNAME=? and PASSWORD=?";
User user = jdbcTemplate.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();
return null;
}
}
}