需求如下: (相比以前的登陆注册添加的新功能如下框)

一、用户登录:(要求如下图)

用户登录总代码结构如下:

User实体类:

package com.itheima.pojo;public class User {private Integer id;private String username;private String password;public Integer getId() {return id;}public void setId(Integer 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;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +'}';}
}

UserServlet:

package com.itheima.service;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import com.itheima.util.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;/***  业务逻辑层*/public class UserService {SqlSessionFactory Factory =SqlSessionFactoryUtils.getSqlSessionFactory();/***  登录方法*/public User login(String username,String password){// 1. 获取SqlSessionSqlSession sqlSession =Factory.openSession();UserMapper userMapper =sqlSession.getMapper(UserMapper.class);// 2. 调用UserMapper接口的查询用户和密码方法User user =userMapper.select(username,password);// 3. 释放资源sqlSession.close();return user;}
}

UserMapper:

package com.itheima.mapper;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;public interface UserMapper {/*** 根据用户名和密码查询用户对象* @param username   @param 参数占位符mybatis完成增删改查里面有解释* @param password* @return*/@Select("select * from tb_user where username = #{username} and password = #{password}")User select(@Param("username") String username, @Param("password") String password);/*** 根据用户名查询用户对象* @param username* @return*/@Select("select * from tb_user where username = #{username}")User selectByUsername(String username);/*** 添加用户* @param user*/@Insert("insert into tb_user values(null,#{username},#{password})")void add(User user);
}

 登录失败/成功结果演示:

登录成功:

登录失败:

记住一句话:重定向会改变URL路径 也就是说我们重定向中写的一个路径,URL会变成该写的路径,转发不改变URL路径

核心代码如下所示:

login.jsp:

先访问login.jsp然后提交到loginServlet路径资源下 再继续其他的操作(转发)

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>login</title><link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px"><form action="/brand-demo/loginServlet" id="form"><h1 id="loginMsg">LOGIN IN</h1><div id="errorMsg">${login_msg}</div><%--${login_msg} 就是我们在LoginServlet资源下登录失败后转发到login页面把登录页面展示给用户,并且把转发时储存到request域当中的数据(用户名或密码错误)拿到展示在登录页面上  ${login_msg}:EL表达式 拿储存在域中数据的--%><p>Username:<input id="username" name="username" type="text"></p><p>Password:<input id="password" name="password" type="password"></p><p>Remember:<input id="remember" name="remember" type="checkbox"></p><div id="subDiv"><input type="submit" class="button" value="login up"><input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;<a href="register.html">没有账号?</a></div></form>
</div></body></html>

LoginServlet:

登录失败的话就跳跳转到login.jsp并携带着储存数据

package com.itheima.web;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
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 javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1、接收客户端用户名和密码String username =request.getParameter("username");String password =request.getParameter("password");// 2、调用service层进行查询UserService userService =new UserService();User user =userService.login(username,password);// 3、判断查询是否有结果if (user != null){// 2. 把user查询出来的数据先封装到Session域当中 (数据保存在了服务器之间共享)HttpSession httpSession =request.getSession();// 存储到Session域中httpSession.setAttribute("user",user);// 1.登录成功 (要求:动态重定向到MVC三层架构讲的商品增删改查操作:SelectAllServlet资源下查询所有)String path =request.getContextPath();response.sendRedirect(path+"/selectAllServlet");} else {// 登录失败// 储存错误提示信息到request域当中 转发给login.jsprequest.setAttribute("login_msg","用户名或密码错误");// 跳转到登录的login.jsp页面request.getRequestDispatcher("/login.jsp").forward(request,response);}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}}

登录成功:把查询到的用户名和密码先储存在Session域当中(因为前几天刚学的Session所以这里用Session 其实同样储存在request域中转发到selectAllServlet路径下也可以),因为后面我们在用户登录成功展示出所有商品的时候要展示出 xxxx欢迎您

Session:服务器中数据共享 (随便转发或者重定向,资源路径下都共享着该Session数据)

这里用重定向的原因是:重定向可以改变URL路径(也就是说我们访问的时候是login.jsp路径 然后URL重定向成selectAllServlet路径)

selectAllServlet:(这里对商品的增删改查回显等 三层架构里面已经写过了)

package com.itheima.web1;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
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.util.List;@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1 调用BrandService完成查询BrandService brandService =new BrandService();List<Brand> brands =brandService.selectAll();// 2 把查询到的数据存入request域当中request.setAttribute("brands",brands);// 3 把存入的数据转发到brand.jsp页面中供用户查看数据request.getRequestDispatcher("/brand.jsp").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

brand.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    <%-- 引入标签库 --%><!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<%-- 拿到Session封装的数据  EL表达式通过$符可以拿到Session域中的数据和request域使用方法一样 --%>
<h1>${user.username},欢迎您</h1><input type="button" value="新增" id="add"><br>
<hr>
<table border="1" cellspacing="0" width="80%"><tr><th>序号</th><th>品牌名称</th><th>企业名称</th><th>排序</th><th>品牌介绍</th><th>状态</th><th>操作</th></tr><c:forEach items="${brands}" var="brand" varStatus="status"><tr align="center"><td>${status.count}</td><td>${brand.brandName}</td><td>${brand.companyName}</td><td>${brand.ordered}</td><td>${brand.description}</td><c:if test="${brand.status ==1}"><td> 启用 </td></c:if><c:if test="${brand.status ==0}"><td> 禁止 </td></c:if><%-- ?id 是把id传送给selectByIdServlet路径下的资源当中 --%><td><a href="/brand-demo/selectByIdServlet?id=${brand.id}">修改</a><a href="/brand-demo/deleteById?id=${brand.id}">删除</a></td></tr></c:forEach></table><script><%-- 这里的 href是添加商品点击按钮后所进入的addBrand.jsp资源路径 --%>document.getElementById("add").onclick = function (){location.href = "/brand-demo/addBrand.jsp";}</script>
</body>
</html>

二、记住用户

写Cookie数据:

login.jsp:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>login</title><link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px"><form action="/brand-demo/loginServlet" id="form"><h1 id="loginMsg">LOGIN IN</h1><div id="errorMsg">${login_msg}</div><%--${login_msg} 就是我们在LoginServlet资源下登录失败后转发到login页面把登录页面展示给用户,并且把转发时储存到request域当中的数据(用户名或密码错误)拿到展示在登录页面上  ${login_msg}:EL表达式 拿储存在域中数据的--%><p>Username:<input id="username" name="username" type="text"></p><p>Password:<input id="password" name="password" type="password"></p><%-- value 的作用就是在复选框中,假设选中了该复选框那么该复选框的值也就是该value的值这里remember是复选框 当我们勾选后 该默认值为“1”--%><p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p><div id="subDiv"><input type="submit" class="button" value="login up"><input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;<a href="register.html">没有账号?</a></div></form>
</div></body></html>

LoginServlet:

用户登录成功后,判断用户是否点了记住我,点了话就发送Cookie数据到客户端浏览器中,没点的话就正常执行登录功能呗,只不过没有发送Cookie数据而已

package com.itheima.web;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1、接收客户端用户名和密码String username =request.getParameter("username");String password =request.getParameter("password");// 获取复选框数据String remember =request.getParameter("remember");// 2、调用service层进行查询UserService userService =new UserService();User user =userService.login(username,password);// 3、判断查询是否有结果if (user != null){// 判断user不为null说明登录成功了// 判断用户是否勾选了记住我 remember// 这里用:"1".equals(remember) 而不用remember.equals("1")// 是为了防止空指针异常 因为remember有可能用户没勾选 为null 然后比较的话会空指针if ("1".equals(remember)){// 勾选了,发送Cookie// 1 创建Cookie对象Cookie c_username =new Cookie("username",username);Cookie c_password =new Cookie("password",password);// 设置Cookie数据在客户端存活的时间c_username.setMaxAge(60*60*24*60);c_password.setMaxAge(60*60*24*60);// 2 发送Cookieresponse.addCookie(c_username);response.addCookie(c_password);}// 2. 把user查询出来的数据先封装到Session域当中 (数据保存在了服务器之间共享)HttpSession httpSession =request.getSession();// 存储到Session域中httpSession.setAttribute("user",user);// 1.登录成功 (要求:动态重定向到MVC三层架构讲的商品增删改查操作:SelectAllServlet资源下查询所有)String path =request.getContextPath();response.sendRedirect(path+"/selectAllServlet");} else {// 登录失败// 储存错误提示信息到request域当中 转发给login.jsprequest.setAttribute("login_msg","用户名或密码错误");// 跳转到登录的login.jsp页面request.getRequestDispatcher("/login.jsp").forward(request,response);}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}}

客户端/浏览器中携带了封装好的用户名和密码的Cookie数据:

获取Cookie数据:(EL表达式)

例如此时浏览器已经登录过一次了,也就是说携带了Cookie封装的数据了:

此时我们login.jsp通过EL表达式获取该username和password数据:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>login</title><link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px"><form action="/brand-demo/loginServlet" id="form"><h1 id="loginMsg">LOGIN IN</h1><div id="errorMsg">${login_msg}</div><%--${login_msg} 就是我们在LoginServlet资源下登录失败后转发到login页面把登录页面展示给用户,并且把转发时储存到request域当中的数据(用户名或密码错误)拿到展示在登录页面上  ${login_msg}:EL表达式 拿储存在域中数据的--%><p>Username:<input id="username" name="username" value="${cookie.username.value}" type="text"></p><p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p><%-- value 的作用就是在复选框中,假设选中了该复选框那么该复选框的值也就是该value的值这里remember是复选框 当我们勾选后 该默认值为“1”--%><p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p><div id="subDiv"><input type="submit" class="button" value="login up"><input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;<a href="register.html">没有账号?</a></div></form>
</div></body></html>

我们再此访问login.jsp页面的时候会帮我们自动填写用户名和密码了:

三、用户注册

register.jsp:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>欢迎注册</title><link href="css/register.css" rel="stylesheet">
</head>
<body><div class="form-div"><div class="reg-content"><h1>欢迎注册</h1><span>已有帐号?</span> <a href="login.jsp">登录</a></div><form id="reg-form" action="/brand-demo/registerServlet" method="get"><table><tr><td>用户名</td><td class="inputs"><input name="username" type="text" id="username"><br><span id="username_err" class="err_msg">${register_msg}</span><%--${register_msg} 通过EL表达式拿到RegisterServlet路径下封装转发过来的数据 (用户名已存在,注册失败)--%></td></tr><tr><td>密码</td><td class="inputs"><input name="password" type="password" id="password"><br><span id="password_err" class="err_msg" style="display: none">密码格式有误</span></td></tr></table><div class="buttons"><input value="注 册" type="submit" id="reg_btn"></div><br class="clear"></form></div>
</body>
</html>

RegisterServlet:

package com.itheima.web;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
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("/registerServlet")
public class RegisterServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1.获取用户注册的用户名和密码String username =request.getParameter("username");String password =request.getParameter("password");// 2. 传递用户名UserService userService =new UserService();User user =userService.register_u(username);// 3. 判断查询的user对象是否为null  不为null说明查询到该用户了 说明已经注册过了if (user !=null){// 用户已经存在了,说明注册失败了// 注册失败后,还跳转到注册的页面request.setAttribute("register_msg","用户名已存在,注册失败");request.getRequestDispatcher("/register.jsp").forward(request,response);}else {// 用户不存在,把封装到User对象中的数据insert注册到数据库中User user1 =new User();user1.setUsername(username);user1.setPassword(password);userService.register_i(user1);// 注册成功后,跳转到登录页面request.setAttribute("register_msg","注册成功,请登录");//数据储存到request域中request.getRequestDispatcher("/login.jsp").forward(request,response);}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

UserServlet:

package com.itheima.service;
import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import com.itheima.util.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;/***  业务逻辑层*/public class UserService {SqlSessionFactory Factory =SqlSessionFactoryUtils.getSqlSessionFactory();/***  登录方法*/public User login(String username,String password){// 1. 获取SqlSessionSqlSession sqlSession =Factory.openSession();UserMapper userMapper =sqlSession.getMapper(UserMapper.class);// 2. 调用UserMapper接口的查询用户和密码方法User user =userMapper.select(username,password);// 3. 释放资源sqlSession.close();return user;}/***  注册方法*  1 先通过用户传递的用户名查询数据库判断是否有该用户*/// 1. 获取SqlSessionpublic User register_u(String username){SqlSession sqlSession =Factory.openSession();UserMapper userMapper =sqlSession.getMapper(UserMapper.class);// 2. 调用UserMapper接口的查询用户方法User user =userMapper.selectByUsername(username);// 3. 释放资源sqlSession.close();return user;}/*** 注册方法* 2 用户不存在的时候 把用户注册的用户名和密码insert添加到数据库当中*  注意:别忘记提交事务*/public void register_i(User user){SqlSession sqlSession =Factory.openSession();UserMapper userMapper =sqlSession.getMapper(UserMapper.class);// 2. 调用UserMapper接口的查询用户方法userMapper.add(user);sqlSession.commit();    // 提交事务// 3. 释放资源sqlSession.close();}}

login.jsp:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>login</title><link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv" style="height: 350px"><form action="/brand-demo/loginServlet" id="form"><h1 id="loginMsg">LOGIN IN</h1><div id="errorMsg">${login_msg} ${register_msg}</div><%--${login_msg} 就是我们在LoginServlet资源下登录失败后转发到login页面把登录页面展示给用户,并且把转发时储存到request域当中的数据(用户名或密码错误)拿到展示在登录页面上  ${login_msg}:EL表达式 拿储存在域中数据的${register_msg} 拿到的是RegisterServlet资源下封装到request域当中的数据通过转发过来(注册成功,请登录)展示在登录的页面上--%><p>Username:<input id="username" name="username" value="${cookie.username.value}" type="text"></p><p>Password:<input id="password" name="password" value="${cookie.password.value}" type="password"></p><%-- value 的作用就是在复选框中,假设选中了该复选框那么该复选框的值也就是该value的值这里remember是复选框 当我们勾选后 该默认值为“1”--%><p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p><div id="subDiv"><input type="submit" class="button" value="login up"><input type="reset" class="button" value="reset">&nbsp;&nbsp;&nbsp;<a href="register.html">没有账号?</a></div></form>
</div></body></html>

结果演示:

用户已存在时:

用户不存在时:

四、验证码     展示&校验

验证码的展示:

代码如下:

验证码工具类:

package com.itheima.util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Random;/*** 生成验证码工具类*/
public class CheckCodeUtil {public static final String VERIFY_CODES = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";private static Random random = new Random();public static void main(String[] args) throws IOException {OutputStream fos = new FileOutputStream("d://a.jpg");String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, fos, 4);System.out.println(checkCode);}/*** 输出随机验证码图片流,并返回验证码值(一般传入输出流,响应response页面端,Web项目用的较多)** @param width 图片宽度* @param height 图片高度* @param os  输出流* @param verifySize 数据长度* @return 验证码数据* @throws IOException*/public static String outputVerifyImage(int width, int height, OutputStream os, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(width, height, os, verifyCode);return verifyCode;}/*** 使用系统默认字符源生成验证码** @param verifySize 验证码长度* @return*/public static String generateVerifyCode(int verifySize) {return generateVerifyCode(verifySize, VERIFY_CODES);}/*** 使用指定源生成验证码** @param verifySize 验证码长度* @param sources    验证码字符源* @return*/public static String generateVerifyCode(int verifySize, String sources) {// 未设定展示源的字码,赋默认值大写字母+数字if (sources == null || sources.length() == 0) {sources = VERIFY_CODES;}int codesLen = sources.length();Random rand = new Random(System.currentTimeMillis());StringBuilder verifyCode = new StringBuilder(verifySize);for (int i = 0; i < verifySize; i++) {verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));}return verifyCode.toString();}/*** 生成随机验证码文件,并返回验证码值 (生成图片形式,用的较少)** @param w* @param h* @param outputFile* @param verifySize* @return* @throws IOException*/public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException {String verifyCode = generateVerifyCode(verifySize);outputImage(w, h, outputFile, verifyCode);return verifyCode;}/*** 生成指定验证码图像文件** @param w* @param h* @param outputFile* @param code* @throws IOException*/public static void outputImage(int w, int h, File outputFile, String code) throws IOException {if (outputFile == null) {return;}File dir = outputFile.getParentFile();//文件不存在if (!dir.exists()) {//创建dir.mkdirs();}try {outputFile.createNewFile();FileOutputStream fos = new FileOutputStream(outputFile);outputImage(w, h, fos, code);fos.close();} catch (IOException e) {throw e;}}/*** 输出指定验证码图片流** @param w* @param h* @param os* @param code* @throws IOException*/public static void outputImage(int w, int h, OutputStream os, String code) throws IOException {int verifySize = code.length();BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);Random rand = new Random();Graphics2D g2 = image.createGraphics();g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 创建颜色集合,使用java.awt包下的类Color[] colors = new Color[5];Color[] colorSpaces = new Color[]{Color.WHITE, Color.CYAN,Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,Color.PINK, Color.YELLOW};float[] fractions = new float[colors.length];for (int i = 0; i < colors.length; i++) {colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];fractions[i] = rand.nextFloat();}Arrays.sort(fractions);// 设置边框色g2.setColor(Color.GRAY);g2.fillRect(0, 0, w, h);Color c = getRandColor(200, 250);// 设置背景色g2.setColor(c);g2.fillRect(0, 2, w, h - 4);// 绘制干扰线Random random = new Random();// 设置线条的颜色g2.setColor(getRandColor(160, 200));for (int i = 0; i < 20; i++) {int x = random.nextInt(w - 1);int y = random.nextInt(h - 1);int xl = random.nextInt(6) + 1;int yl = random.nextInt(12) + 1;g2.drawLine(x, y, x + xl + 40, y + yl + 20);}// 添加噪点// 噪声率float yawpRate = 0.05f;int area = (int) (yawpRate * w * h);for (int i = 0; i < area; i++) {int x = random.nextInt(w);int y = random.nextInt(h);// 获取随机颜色int rgb = getRandomIntColor();image.setRGB(x, y, rgb);}// 添加图片扭曲shear(g2, w, h, c);g2.setColor(getRandColor(100, 160));int fontSize = h - 4;Font font = new Font("Algerian", Font.ITALIC, fontSize);g2.setFont(font);char[] chars = code.toCharArray();for (int i = 0; i < verifySize; i++) {AffineTransform affine = new AffineTransform();affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2, h / 2);g2.setTransform(affine);g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);}g2.dispose();ImageIO.write(image, "jpg", os);}/*** 随机颜色** @param fc* @param bc* @return*/private static Color getRandColor(int fc, int bc) {if (fc > 255) {fc = 255;}if (bc > 255) {bc = 255;}int r = fc + random.nextInt(bc - fc);int g = fc + random.nextInt(bc - fc);int b = fc + random.nextInt(bc - fc);return new Color(r, g, b);}private static int getRandomIntColor() {int[] rgb = getRandomRgb();int color = 0;for (int c : rgb) {color = color << 8;color = color | c;}return color;}private static int[] getRandomRgb() {int[] rgb = new int[3];for (int i = 0; i < 3; i++) {rgb[i] = random.nextInt(255);}return rgb;}private static void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private static void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private static void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(40) + 10; // 50;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}
}

分析该工具类:

register.jsp:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>欢迎注册</title><link href="css/register.css" rel="stylesheet">
</head>
<body><div class="form-div"><div class="reg-content"><h1>欢迎注册</h1><span>已有帐号?</span> <a href="login.jsp">登录</a></div><form id="reg-form" action="/brand-demo/registerServlet" method="get"><table><tr><td>用户名</td><td class="inputs"><input name="username" type="text" id="username"><br><span id="username_err" class="err_msg">${register_msg}</span><%--${register_msg} 通过EL表达式拿到RegisterServlet路径下封装的数据 (用户名已存在,注册失败)--%></td></tr><tr><td>密码</td><td class="inputs"><input name="password" type="password" id="password"><br><span id="password_err" class="err_msg" style="display: none">密码格式有误</span></td></tr><tr><td>验证码</td><td class="inputs"><input name="checkCode" type="text" id="checkCode"><img id="checkCodeImg" src="/brand-demo/checkCodeServlet"><a href="#" id="changeImg">看不清?</a></td></tr></table><div class="buttons"><input value="注 册" type="submit" id="reg_btn"></div><br class="clear"></form>
</div><script>/* 给看不清?添加单击事件 也就是说每点击一次看不清? 就会重新跳转到/brand-demo/checkCodeServlet*   记得加时间戳  因为存在缓存情况* */document.getElementById("changeImg").onclick =function (){document.getElementById("checkCodeImg").src ="/brand-demo/checkCodeServlet?"+new Date().getMilliseconds();}
</script>
</body>
</html>

CheckCodeServlet:

该资源下的作用:在页面上随机生成4位数的验证码 (位数可修改)

package com.itheima.web;import com.itheima.util.CheckCodeUtil;import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {/***     生成验证码 *        通过路径的访问 展示在注册页面上 (后面的数字4 代表验证码个数 可修改)*/ServletOutputStream os =response.getOutputStream();String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

开启服务器访问register.jsp:

验证码的校验:

CheckCodeServlt:

程序生成的验证码:

将程序生成的验证码存储在Session域中 (服务器之间资源共享)

package com.itheima.web;
import com.itheima.util.CheckCodeUtil;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 程序随机生成验证码ServletOutputStream os =response.getOutputStream();String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);// 把程序随机生成的验证码存入Session域中 (用于和用户输入的验证码比对)HttpSession session =request.getSession();session.setAttribute("checkCodeGen",checkCode);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

RegisterServlet:(认真看代码 有细节)

package com.itheima.web;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
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 javax.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1.获取用户注册的用户名和密码String username =request.getParameter("username");String password =request.getParameter("password");// 获取用户输入的验证码String checkCode =request.getParameter("checkCode");// 获取程序随机生成的验证码    (根据key获取值)HttpSession session =request.getSession();// Object类型转换成String类型 (用户输入的为String类型 转成String做对比)String checkCodeGen = (String) session.getAttribute("checkCodeGen");// 注册之前作对比 如果验证码都不正确就没必要再判断往下走代码 判断查询的user对象是否为null了// 程序生成的验证码肯定不会为null 所以比较的时候放在最前面 作用:防止空指针异常// equalsIgnoreCase : 是不区分大小写比较的方法 (验证码一般不需要比较大小写)if (!checkCodeGen.equalsIgnoreCase(checkCode)){request.setAttribute("register_msg","验证码错误");request.getRequestDispatcher("/register.jsp").forward(request,response);return; // 直接结束代码即可}// 2. 传递用户名UserService userService =new UserService();User user =userService.register_u(username);// 3. 判断查询的user对象是否为null  不为null说明查询到该用户了 说明已经注册过了if (user !=null){// 用户已经存在了,说明注册失败了// 注册失败后,还跳转到注册的页面request.setAttribute("register_msg","用户名已存在,注册失败");request.getRequestDispatcher("/register.jsp").forward(request,response);}else {// 用户不存在,把封装到User对象中的数据insert注册到数据库中User user1 =new User();user1.setUsername(username);user1.setPassword(password);userService.register_i(user1);// 注册成功后,跳转到登录页面request.setAttribute("register_msg","注册成功,请登录");//数据储存到request域中request.getRequestDispatcher("/login.jsp").forward(request,response);}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

register.jsp:

<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>欢迎注册</title><link href="css/register.css" rel="stylesheet">
</head>
<body><div class="form-div"><div class="reg-content"><h1>欢迎注册</h1><span>已有帐号?</span> <a href="login.jsp">登录</a></div><form id="reg-form" action="/brand-demo/registerServlet" method="post"><table><tr><td>用户名</td><td class="inputs"><input name="username" type="text" id="username"><br><span id="username_err" class="err_msg" >${register_msg}</span><%--${register_msg} 通过EL表达式拿到RegisterServlet路径下封装转发过来的数据 (用户名已存在,注册失败)--%></td></tr><tr><td>密码</td><td class="inputs"><input name="password" type="password" id="password"><br><span id="password_err" class="err_msg" style="display: none">密码格式有误</span></td></tr><tr><td>验证码</td><td class="inputs"><input name="checkCode" type="text" id="checkCode"><img id="checkCodeImg" src="/brand-demo/checkCodeServlet"><a href="#" id="changeImg" >看不清?</a></td></tr></table><div class="buttons"><input value="注 册" type="submit" id="reg_btn"></div><br class="clear"></form></div><script>/* 给看不清?添加单击事件 也就是说每点击一次看不清? 就会重新跳转到/brand-demo/checkCodeServlet*   记得加时间戳  因为存在缓存情况* */document.getElementById("changeImg").onclick = function () {document.getElementById("checkCodeImg").src = "/brand-demo/checkCodeServlet?"+new Date().getMilliseconds();}</script>
</body>
</html>

开启服务器访问register.jsp:

用户登录(记住用户)用户注册(验证码) [运用Cookie Session技术]相关推荐

  1. .net session 有效时间_Python中requests模拟登录的三种方式(携带cookie/session进行请求网站)...

    这篇文章主要介绍了python中requests模拟登录的三种方式(携带cookie/session进行请求网站),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋 ...

  2. Cookie实现用户登录记住密码,实现自动登录

    什么是Cookie 在java是一个类,一对键和值组成,键值都是字符串类型,每个cookie只能保存一对键和值.每个cookie只能保存最大4K的数据 案列应用 保存用户名和密码在浏览器端,Cooki ...

  3. ajax用户登录模块,ajax用户注册模块

    ajax用户注册模块 内容精选 换一换 用户输入码流给VDEC解码,某些帧或所有帧都没有触发回调函数,用户收不到解码结果.码流中某些帧是坏帧,导致语法解析不出这些帧的含义,或者解码这些帧失败,从而不调 ...

  4. jsp实现简单用户登录(用户7天内免登录)

    (1)登陆页面:login.jsp <%@ page language="java" contentType="text/html; charset=utf-8&q ...

  5. 实战SSM_O2O商铺_48【用户登录】用户登录Dao-Service-Controller-View层的开发

    文章目录 概述 Dao层 接口 mapper映射文件 LocalAuthDao.xml 单元测试 Service层 接口 实现类 MD5密码加密工具类 单元测试 Controller层 LocalAu ...

  6. 大数据技术之_01_Linux学习_01_linux的入门+VM和linux的安装+linux的目录结构+远程登录到linux服务器+vi和vim编辑器+开机、重启和用户登录注销+用户管理+用户组管理

    大数据学习之_01_Linux学习_01 1 linux的入门 1.1 Linux的介绍 2 VM和linux的安装 2.1 安装vm和Centos 2.1.1 基本说明 2.1.2 CentOS安装 ...

  7. 查看有多少个linux用户登录,Linux用户查看系统有多少用户在登录

    作为系统管理员,你可能经常会(在某个时候)需要查看系统中有哪些用户正在活动.有些时候,你甚至需要知道他(她)们正在做什么.本文为我们总结了4种查看系统用户信息(通过编号(ID))的方法. 1. 使用w ...

  8. python用户登录_python用户登录系统

    本文实例为大家分享了用户登录系统python实现代码,供大家参考,具体内容如下 注意事项: 1.使用python3执行程序.按提示输入1或2,登录或退出程序 2.输入用户名后,如果用户名被锁定及无效用 ...

  9. 用户登录python_python用户登录系统

    本文实例为大家分享了用户登录系统python实现代码,供大家参考,具体内容如下 注意事项: 1.使用python3执行程序.按提示输入1或2,登录或退出程序 2.输入用户名后,如果用户名被锁定及无效用 ...

最新文章

  1. [HNOI2016]最小公倍数
  2. Java 设计模式之外观模式
  3. ASP.NET Core 跨平台图形验证码实现
  4. 【Python】Python中对目录路径的要求
  5. PyCharm光标变粗的解决办法
  6. OSChina 周日乱弹 —— 昨天夜生活很丰满
  7. PHP去除BOM头的方法
  8. SpringCloud系列-Ribbon的基本应用
  9. HTML与XHTML区别
  10. 配置Typescript+Node环境
  11. 学生信息管理系统(php MySql),基于PHP学生信息管理系统设计系统设计(MySQL)(含录像)...
  12. android高德地图热力图,没有编程基础也可通过高德地图完成炫酷的热力图分析...
  13. java堆栈类_JAVA 堆栈类(Stack)的使用
  14. 计算机音乐制作旋律教学,旋律创作的基本规律 管窥小学音乐旋律创作教学
  15. 汽车分类(奔驰G系列和奔驰c系列)
  16. Java-翁恺进阶 城堡游戏的前世今生
  17. 问卷答题模板:包括单选,多选,以及图片模式
  18. 免费音乐素材网站推荐 视频剪辑自媒体运营必备
  19. JVM源码分析之Metaspace解密
  20. 少即是多:视觉SLAM的点稀疏化(IROS 2022)

热门文章

  1. 在有循环嵌套时, 要把大循环写在内, 小循环写在外, 原因在此
  2. Python中的log文件(详细教程)
  3. Java、JSP公交车管理系统
  4. 配置无线用户接入WLAN实验
  5. Python办公自动化实战 04 | Python-docx库:Python与Word的完美结合_综合案例快速上手
  6. 3-1 郭老师的冰糖葫芦 c++
  7. VUE:用vue实现的计算器实例
  8. Unity-默认渲染管线-刻晴卡渲shader
  9. 硬件设计基础----通信协议UART
  10. msgpack php 安装,安装msgpack-2.0.2报错