目录
- 引出
- 登陆功能---从html到jsp
- 1.登陆--用post请求
- 2.用html文件的form表单登陆
- (1)index.html页面
- (2)login.html登陆的页面
- (3)LoginServlet.java处理输入信息的代码
- (4)登陆成功:
 
- 3.如果失败在原页面显示信息----用jsp文件登陆
- (1)login.jsp页面
- (2)LoginServlet.java处理登陆业务---共享msg
 
 
- 注册功能---注册验证码
- 4.注册逻辑 和 注册成功后跳转到登陆页面
- 5.如何防止用户恶意注册----用验证码限制
- (1)前端显示验证码
- (2)后端判断验证是否正确
- (3)完整代码
 
 
- 登陆成功和退出登陆
- 6.登陆成功和退出登陆---保存session和删除session
- (1)前端页面,comIndex.jsp
- (2)进行登陆,保存session
- (3)退出系统servlet,LogoutServlet.jsp
 
 
- 总结
引出
1.验证用户名密码正确的思路;
 2.从html文件到jsp文件的登陆进化—静态到动态;
 3.用验证码的方式防止不断注册;
 4.注册成功后再跳转到登陆页面—重定向;
 4.如何保存登陆的用户信息----session;
登陆功能—从html到jsp
1.登陆–用post请求
思路:
1.通过username 和 password 查询对象出来,如果对象有,登陆成功,否则失败;
2.通过username 和 password 查询数量,如果数量为1,登陆成功,否则失败;
3.【推荐】SpringSecurity 推荐的方式:用username 查一个对象出来;
(1)查不到,登陆失败(没有注册过,数据库没有这个用户名);
(2)查到了,用户名正确,用查询出来的这一条记录和前端发送过来的密码对比:
 如果正确,登陆成功,否则,登陆失败;
dao层的接口和实现:
接口要有:(1)新增一个数据到数据库;(2)根据用户名查询一条记录出来;
dao层的接口:
package com.tianju.dao;
import com.tianju.entity.ComUser;
/**
 * 公司用户的Dao类
 */
public interface IComUserDao {
    /**
     * 新增一个公司用户
     * @param comUser 新增用户
     * @return 影响行数
     */
    Integer add(ComUser comUser);
    /**
     * 根据用户名查一条记录出来
     * @param username 查询的用户名
     * @return 查询出的用户
     */
    ComUser queryByUsername(String username);
}
dao接口的实现:
package com.tianju.dao.impl;
import com.tianju.dao.IComUserDao;
import com.tianju.entity.ComUser;
import com.tianju.util.DBUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.util.List;
public class ComUserDaoImpl implements IComUserDao {
    private JdbcTemplate db = DBUtils.getJdbcTemplate();
    public RowMapper<ComUser> rowMapper = new BeanPropertyRowMapper<>(ComUser.class);
    @Override
    public Integer add(ComUser comUser) {
        String sql = "INSERT INTO com_user(id,username,password,sex,birthday)" +
                "values (null,?,?,?,?)";
        return db.update(sql,comUser.getUsername(),comUser.getPassword(),comUser.getSex(),comUser.getBirthday());
    }
    @Override
    public ComUser queryByUsername(String username) {
        String sql = "SELECT * FROM com_user WHERE username=?";
        List<ComUser> find = db.query(sql, rowMapper,username);
        if (find.size()>0){
            return find.get(0);
        }
        return null;
    }
}
2.用html文件的form表单登陆

(1)index.html页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img src="img/register.jpg" width="200px"><br>
<a href="/day01/html/login.html" target="_blank">登陆</a><br>
<a href="html/register.html" target="_blank">注册</a><br>
<a href="html/idcard.html" target="_blank">身份证归属地</a><br>
<a href="/day01/html/loginNew.html">新版登陆页面</a><br>
<a href="/day01/bookTypes/list">显示图书类型的表格--前端在java中拼出来</a><br>
<a href="/day01/bookList/jsp">显示图书类型的表格--用jsp</a>
</body>
</html>

(2)login.html登陆的页面
其中密码输入的input框的type设置成 password
密码 :<input type="password" name="password"><br>

action 要用绝对路径 :/项目名/链接
1)有 / 为绝对路径,从ip/端口/day01/开始拼接 ,会从localhost:8080位置开始拼接路径
 2)无 / 为相对路径,浏览器会删除最后一级目录,然后把相对目录地址拼接上去
如果是绝对路径,会从localhost:8080位置开始拼接路径
浏览器路径为:localhost:8080/day01/a
<a href="/b">跳转</a>
跳转后路径为:localhost:8080/b
如果是相对路径,浏览器会删除最后一级目录,然后把相对目录地址拼接上去
浏览器路径为:localhost:8080/day01/a
<a href="b">跳转</a>
跳转后路径为:localhost:8080/day01/b
get和post
 查询用get:链接里显示输入的值;写到请求头中
 登陆用post:链接里不会显示输入的值;写到请求体中
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登陆的页面</title>
</head>
<body>
    <form action="/day01/loginUserNew" method="post">
        <h1>新版登陆页面</h1>
        <img src="../img/register.jpg" width="200px"><br>
        用户名:<input type="text" name="username"><br>
        密   码:<input type="password" name="password"><br>
        <input type="submit" value="登陆">
        <input type="reset" value="重置">
    </form>
    <a href="../index.html">返回主界面</a>
</body>
</html>

(3)LoginServlet.java处理输入信息的代码
业务流程:
1)输入不为空;
2)验证用户名和密码;
2)登陆成功;
/**
 * 用户登陆的服务,注意不能用log
 * 1.username + password 查询对象出来,对象有,登陆成功,否则失败;
 * 2.查询数量出来,1成功,否则失败;
 * 3.【建议】springSecurity 推荐,用username 查一个对象;
 *     3.1 查不到,登陆失败(没有注册过,数据库无这个用户名);
 *     3.2 查到了,用户名正确,就用这一条记录的密码和前端发送的密码对比;
 *         如果正确,登陆成功,不登录失败;
 */
@WebServlet("/loginUserNew")
public class LoginServlet extends HttpServlet {
    private IUserService  userService = new UserServiceImpl();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 解决编码的问题
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");
        // 获取前端传来的用户名
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            resp.getWriter().write("<h1>必填项为空</h1>");
            return;
        }
        // 登陆错误,重新输入
        User user = userService.findByUsername(username);
        if (user==null || !password.equals(user.getPassword())){
            resp.getWriter().write("<h1>用户名|密码错误</h1>");
            return;
        }
        String out = "<h1>用户名"+user.getUsername() +"/"+ user.getNickname() +"登陆成功"+"</h1>";
        resp.getWriter().write(out);
    }
}

(4)登陆成功:

3.如果失败在原页面显示信息----用jsp文件登陆
(1)login.jsp页面
用一个span框,获取共享的msg信息
    <span style="color: darkred">${msg}</span><br>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登陆页面e</title>
</head>
<body>
<form action="/day06/comUser/login" method="post">
    用户名:<input type="text" name="username"><br>
    密  码:<input type="password" name="password"><br>
    <span style="color: darkred">${msg}</span><br>
    <input type="submit" value="登陆">
</form>
</body>
</html>
(2)LoginServlet.java处理登陆业务—共享msg
请求转发,内部转发,jsp本质也是servlet
        if (comUser==null || !comUser.getPassword().equals(SecureUtil.md5(password))){
            req.setAttribute("msg", "用户名 | 密码错误");
            req.getRequestDispatcher("/comUser/login.jsp").forward(req, resp);
            return;
        }
完整代码:
/**
 * 用户登陆的servlet
 */
@WebServlet("/comUser/login")
public class LoginServlet extends HttpServlet {
    private IComUserService comUserService = new ComUserServiceImpl();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 编码问题
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");
        // 输入不为空
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            // 输入为空
            req.setAttribute("msg", "输入为空,请检查");
            req.getRequestDispatcher("/comUser/login.jsp").forward(req, resp);
            return;
        }
        // 进行验证
        ComUser comUser = comUserService.queryByUsername(username);
        if (comUser==null || !comUser.getPassword().equals(SecureUtil.md5(password))){
            req.setAttribute("msg", "用户名 | 密码错误");
            req.getRequestDispatcher("/comUser/login.jsp").forward(req, resp);
            return;
        }
        // 跳转到操作页面
        resp.sendRedirect(req.getContextPath()+"/compMess/comIndex.jsp");
        
    }
}

注册功能—注册验证码
4.注册逻辑 和 注册成功后跳转到登陆页面
用验证码的方式防止恶意注册;
注册成功重定向到登陆页面:
		// 5.注册成功跳转到登陆页面
        resp.sendRedirect(req.getContextPath()+"/comUser/login.jsp");
5.如何防止用户恶意注册----用验证码限制
(1)前端显示验证码
验证码的图片请求servlet
    验证码:<input type="text" name="imgCode"><img src="/day06/register/image/get">
<%--    如果要让验证码在点击时自动更新--%>
    验证码:<input type="text" name="imgCode">
    <img src="/day06/register/image/get" οnclick="this.src='/day06/register/image/get?'+new Date().getMilliseconds()">
servlet处理请求:
(1)把验证码—4位数字存到session中;
(2)把验证码的图片放到响应中,发送给前端jsp,进行展示;
@WebServlet("/register/image/get")
public class ImageServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 随机生成验证码
        String randomStr = ImageCodeUtils.getRandomStr(4);
        // 验证码存到session空间中
        HttpSession session = req.getSession();
        session.setAttribute("yzm", randomStr);
        // 根据验证码在缓存中生成一张图片
        BufferedImage bufferedImage = ImageCodeUtils.createImageCode(100, 36, randomStr);
        // 把缓存中的图片以png的格式,放到响应的输出流中
        ImageIO.write(bufferedImage, "png", resp.getOutputStream());
    }
}
注意这里有个错误:共享的时候不能是session,查了好久这个bug

一个卡了一会儿的bug

生成的图片分析:

(2)后端判断验证是否正确
在图片的servlet中,把图片的验证码4位数字存到session空间中;
        // 验证码存到session空间中
        HttpSession session = req.getSession();
        session.setAttribute("yzm", randomStr);
在注册的register的servlet中,获取session,从session中获取验证码数字,进行判断
- 忽略大小写
        // +++++判断验证码是否正确
        HttpSession session = req.getSession();
        // 从session中获取验证码
        String yzm = (String)session.getAttribute("yzm");
        // 忽略大小写 .equalsIgnoreCase
        if (!yzm.equalsIgnoreCase(imgCode)){
            req.setAttribute("msg", "验证码不正确");
            req.getRequestDispatcher("/comUser/register.jsp").forward(req, resp);
            return;
        }
验证码对比流程:

(3)完整代码
处理注册业务的RegisterServlet.java文件
@WebServlet("/comUser/register")
public class RegisterServlet extends HttpServlet {
    private IComUserService comUserService = new ComUserServiceImpl();
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 解决编码问题
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");
        // 用户注册的业务逻辑
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String rePassword = req.getParameter("rePassword");
        String sex = req.getParameter("gender");
        String birthday = req.getParameter("birthday");
        System.out.println(username+password+rePassword+sex+birthday);
        // +++加入+验证码输入
        String imgCode = req.getParameter("imgCode");
        // 1.输入不为空;
        if (StringUtils.isBlank(username)
        || StringUtils.isBlank(password)
        || StringUtils.isBlank(rePassword)
        || StringUtils.isBlank(sex)
        || StringUtils.isBlank(birthday)
        || StringUtils.isBlank(imgCode)){
            // 如果为空,显示一条信息;转发给jsp
            req.setAttribute("msg", "输入为空,请检查");
            req.getRequestDispatcher("/comUser/register.jsp").forward(req, resp);
            return;
        }
        // +++++判断验证码是否正确
        HttpSession session = req.getSession();
        // 从session中获取验证码
        String yzm = (String)session.getAttribute("yzm");
        // 忽略大小写 .equalsIgnoreCase
        if (!yzm.equalsIgnoreCase(imgCode)){
            req.setAttribute("msg", "验证码不正确");
            req.getRequestDispatcher("/comUser/register.jsp").forward(req, resp);
            return;
        }
        // 2.用户名不重复;
        ComUser comUserDb = comUserService.queryByUsername(username);
        if (comUserDb!=null){
            // 用户名重复
            req.setAttribute("msg", "用户名重复,请重新输入");
            req.getRequestDispatcher("/comUser/register.jsp").forward(req, resp);
            return;
        }
        // 3.两次密码输入一致;
        if (!password.equals(rePassword)){
            // 两次密码不一致
            req.setAttribute("msg", "两次密码输入不一致,请检查");
            req.getRequestDispatcher("/comUser/register.jsp").forward(req, resp);
            return;
        }
        // 进行密码加密存储
        ComUser comUser = new ComUser();
        comUser.setPassword(SecureUtil.md5(password));
        comUser.setUsername(username);
        try {
            comUser.setBirthday(sdf.parse(birthday));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        comUser.setSex(sex);
        System.out.println(comUser);
        // 4.保存信息到数据库
        comUserService.add(comUser);
        // 5.注册成功跳转到登陆页面
        resp.sendRedirect(req.getContextPath()+"/comUser/login.jsp");
    }
}
生成验证码的ImageServlet.java文件:
/**
 * 验证码的servlet
 * 随机生成验证码,验证码存到session空间中;
 * 把验证码图片以png的格式,放到响应的输出流中;
 */
@WebServlet("/register/image/get")
public class ImageServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 随机生成验证码
        String randomStr = ImageCodeUtils.getRandomStr(4);
        // 验证码存到session空间中
        HttpSession session = req.getSession();
        session.setAttribute("yzm", randomStr);
        // 根据验证码在缓存中生成一张图片
        BufferedImage bufferedImage = ImageCodeUtils.createImageCode(100, 36, randomStr);
        // 把缓存中的图片以png的格式,放到响应的输出流中
        ImageIO.write(bufferedImage, "png", resp.getOutputStream());
    }
}
ImageCodeUtils.java --生成验证码图片的工具类
package com.tianju.util;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
/**
 * 生成图片验证码
 */
public class ImageCodeUtils {
    //根据传入的位数,生成随机字符
    public static String getRandomStr(int length)
    {
        String s = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
//        Random random = new Random(System.currentTimeMillis());
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int i1 = random.nextInt(s.length());
            sb.append(s.charAt(i1));
        }
        return sb.toString();
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        for (int i = 0; i < 100; i++) {
            Thread.sleep(10);
            String randomStr = getRandomStr(4);
            System.out.println(randomStr);
        }
//        //BuffereImage 图片缓冲流
//        BufferedImage bufferedImage = createImageCode(100, 34, "ABCD");//生成图片的缓冲流
//        //把缓冲流,写到某个输出流
//        ImageIO.write(bufferedImage,"jpg",new FileOutputStream("/Users/edz/Desktop/11.jpg"));
    }
    public static BufferedImage createImageCode(int width, int height, String code) {
        int codeSize = code.length();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Random rand = new Random();
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        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, width, height);
        Color c = getRandColor(200, 250);
        g2.setColor(c);// 设置背景色
        g2.fillRect(0, 2, width, height - 4);
        // 绘制干扰线
        Random random = new Random();
        g2.setColor(getRandColor(160, 200));// 设置线条的颜色
        for (int i = 0; i < 20; i++) {
            int x = random.nextInt(width - 1);
            int y = random.nextInt(height - 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 * width * height);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int rgb = getRandomIntColor();
            image.setRGB(x, y, rgb);
        }
        shear(g2, width, height, c);// 使图片扭曲
        g2.setColor(getRandColor(100, 160));
        int fontSize = height - 4;
        Font font = new Font("Algerian", Font.ITALIC, fontSize);
        g2.setFont(font);
        char[] chars = code.toCharArray();
        for (int i = 0; i < codeSize; i++) {
            AffineTransform affine = new AffineTransform();
            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
                    (width / codeSize) * i + fontSize / 2, height / 2);
            g2.setTransform(affine);
            g2.drawChars(chars, i, 1, ((width - 10) / codeSize) * i + 5, height / 2 + fontSize / 2 - 10);
        }
        g2.dispose();
        return image;
    }
    private static Color getRandColor(int fc, int bc) {
        Random random = ThreadLocalRandom.current();
        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() {
        Random random = ThreadLocalRandom.current();
        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) {
        Random random = ThreadLocalRandom.current();
        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 = (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * phase) / 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) {
        Random random = ThreadLocalRandom.current();
        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 = (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * phase) / 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);
            }
        }
    }
}
登陆成功和退出登陆
6.登陆成功和退出登陆—保存session和删除session
登陆成功后,将登陆成功的用户存到session----用于确定当前的操作是谁做的
        // +登陆成功的用户存到session----用于确定当前的操作是谁做的
        req.getSession().setAttribute("user", userDb);
退出登陆后,把保存的session信息删除,并重新回到登陆页
        HttpSession session = req.getSession();
        session.invalidate(); // 清理session
        resp.sendRedirect(req.getContextPath()+"/user/login.jsp");
完整的业务逻辑代码:

(1)前端页面,comIndex.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆成功的index页面</title>
</head>
<body>
<a href="/day06/company/messList" target="iframe">查询公司所有信息</a>
<a href="/day06/user/logout">退出系统</a>
<iframe width="100%" height="80%" name="iframe"></iframe>
</body>
</html>
(2)进行登陆,保存session
/**
 * 用户登陆的servlet
 */
@WebServlet("/comUser/login")
public class LoginServlet extends HttpServlet {
    private IComUserService comUserService = new ComUserServiceImpl();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 编码问题
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html;charset=utf-8");
        // 输入不为空
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
            // 输入为空
            req.setAttribute("msg", "输入为空,请检查");
            req.getRequestDispatcher("/comUser/login.jsp").forward(req, resp);
            return;
        }
        // 进行验证
        ComUser comUser = comUserService.queryByUsername(username);
        if (comUser==null || !comUser.getPassword().equals(SecureUtil.md5(password))){
            req.setAttribute("msg", "用户名 | 密码错误");
            req.getRequestDispatcher("/comUser/login.jsp").forward(req, resp);
            return;
        }
        // ++++++登陆成功的用户对象存储到session中=====用户确定后续的操作是谁做的
        req.getSession().setAttribute("user", comUser);
        // 跳转到操作页面---重定向
        resp.sendRedirect(req.getContextPath()+"/compMess/comIndex.jsp");
    }
}
(3)退出系统servlet,LogoutServlet.jsp
/**
 * 退出登陆的servlet,清除session缓存
 */
@WebServlet("/user/logout")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        session.invalidate(); // 清除session
        // 重定向,回到登陆页面
        resp.sendRedirect(req.getContextPath()+"/index.jsp");
    }
}
总结
1.验证用户名密码正确:通过username查一条信息出来,对比密码;
 2.用jsp文件代替html文件实现共享msg的提醒,比如用户名|密码不正确;
 3.用验证码的方式防止不断注册,点击图片自动更细;
 4.注册成功后再跳转到登陆页面—重定向;
 4.用session空间保存登陆成功的用户对象;


















