JavaWeb开发实战(二)

本文涉及的产品
简介: JavaWeb开发实战(二)

6.5 创建登录业务的Filter

创建UserLoginFilter实现未登录拦截。

package com.zj.web.filter;
import com.sun.org.apache.bcel.internal.Const;
import com.zj.commons.Constants;
import com.zj.pojo.User;
import jdk.nashorn.internal.objects.NativeArray;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import java.io.IOException;
/*判断当前客户端浏览器是否登录的Filter*/
@WebFilter("/*")
public class UserLoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String uri = request.getRequestURI();
        //判断当前路径是否是login.jsp或者login.do,放行这两个资源,还需要放行验证码图片。
        if (uri.indexOf("login.jsp") != -1 || uri.indexOf("login.do") != -1 || uri.indexOf("ValidateCodeServlet.do")!= -1) {
            filterChain.doFilter(request,response);
        }else {
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute(Constants.USER_SESSION_KEY);
            if (user != null) {
                filterChain.doFilter(request,response);
            }else {
                request.setAttribute(Constants.REQUEST_MSG,"不登陆不好使!(⊙o⊙)?");
                request.getRequestDispatcher("login.jsp").forward(request, response);
            }
        }
    }
    @Override
    public void destroy() {
    }
}

6.6 实现用户只能在一处登录

当前的一个账号可以在多个浏览器登录,我们要实现的是账号在另一个浏览器登陆的时候会挤掉当前浏览器的账户。

实现的原理是将当前用户的session放在context中缓存,用户在当前浏览器登录的时候首先查看context中是否存在当前用户的session信息,存在的话表示当前用户在其他浏览器已经登录过了,则删除该之前浏览器和服务端之间的会话session,重新建立当前浏览器与服务端的session连接,并将该session保存到context中。

6.7 解决HttpSession超时销毁时的异常问题

6.6实现了用户只能在一处登录,但是session有自动销毁的时间是半个小时。此时session被tomcat销毁但是context还保存着已经被销毁的session的信息,再使用另一个浏览器登陆时仍然能拿到这个被销毁的session,再一次销毁这个session的时候就会报错,因为之前已经被tomcat销毁了嘛。此时可以通过listener监听器来监听session的声明周期。

package com.zj.web.listener;
import com.zj.commons.Constants;
import com.zj.pojo.User;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class HttpSessionLifeListener implements HttpSessionListener {
    /*HttpSession被销毁之前触发该方法*/
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        //获取servletContext对象,将保存在context中的即将被销毁的session删除。
        HttpSession session = se.getSession();
        ServletContext servletContext = session.getServletContext();
        User user = (User) servletContext.getAttribute(Constants.USER_SESSION_KEY);
        servletContext.removeAttribute(user.getUserid()+"");
    }
}

6.8 在登录中添加验证码功能

首先将生成验证码的servlet工具类添加到项目中

package com.zj.commons;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/ValidateCodeServlet.do")
public class ValidateCodeServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 在内存中创建图象
        int width = 70, height = 45;
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);
        // 获取图形上下文
        Graphics g = image.getGraphics();
        // 生成随机类
        Random random = new Random();
        // 设定背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        // 设定字体
        g.setFont(new Font("Times New Roman", Font.PLAIN, 20));
        // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 155; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        // 取随机产生的认证码(4位数字)
        String sRand = "";
        for (int i = 0; i < 4; i++) {
            String rand = String.valueOf(random.nextInt(10));
            sRand += rand;
            // 将认证码显示到图象中
            g.setColor(new Color(20 + random.nextInt(110), 20 + random
                    .nextInt(110), 20 + random.nextInt(110)));
            // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
            g.drawString(rand, 13 * i + 6, 16);
        }
        // 图象生效
        g.dispose();
        try {
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            System.out.println("验证码图片产生出现错误:" + e.toString());
        }
        //保存验证码到Session
        request.getSession().setAttribute("randStr", sRand);
    }
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
    /*
     * 给定范围获得随机颜色
     */
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        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);
    }
}

修改登录页面在login.jsp中添加验证码标签img,定义函数change每次点击验证码都会更换。

<img id="code" src="ValidateCodeServlet.do" onclick="change"/>
/*点击验证码图片生成验证码*/
        function change() {
           $("#code").attr("src","ValidateCodeServlet.do?"+Math.random())
        }

在 UserLoginFilter过滤器中放行验证码图片资源。

if (uri.indexOf("login.jsp") != -1 || uri.indexOf("login.do") != -1 || uri.indexOf("ValidateCodeServlet.do")!= -1) {
            filterChain.doFilter(request,response);
}

在UserLoginServlet中实现验证码的校验。

 

6.9 用户退出功能

在left.jsp页面添加退出功能的标签。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
</html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>无标题文档</title>
    <link href="css/style.css" rel="stylesheet" type="text/css" />
    <script language="JavaScript" src="js/jquery.js"></script>
    <script type="text/javascript">
        $(function(){
            //导航切换
            $(".menuson .header").click(function(){
                var $parent = $(this).parent();
                $(".menuson>li.active").not($parent).removeClass("active open").find('.sub-menus').hide();
                $parent.addClass("active");
                if(!!$(this).next('.sub-menus').size()){
                    if($parent.hasClass("open")){
                        $parent.removeClass("open").find('.sub-menus').hide();
                    }else{
                        $parent.addClass("open").find('.sub-menus').show();
                    }
                }
            });
            // 三级菜单点击
            $('.sub-menus li').click(function(e) {
                $(".sub-menus li.active").removeClass("active")
                $(this).addClass("active");
            });
            $('.title').click(function(){
                var $ul = $(this).next('ul');
                $('dd').find('.menuson').slideUp();
                if($ul.is(':visible')){
                    $(this).next('.menuson').slideUp();
                }else{
                    $(this).next('.menuson').slideDown();
                }
            });
        })
    </script>
</head>
<body style="background:#f0f9fd;">
<div class="lefttop"><span></span>导航菜单</div>
<dl class="leftmenu">
    <dd>
        <div class="title"><span><img src="images/leftico03.png" /></span>用户管理</div>
        <ul class="menuson">
            <li><cite></cite><a href="userAdd.jsp" target="rightFrame">添加用户</a><i></i></li>
            <li><cite></cite><a href="findUser.jsp" target="rightFrame">查询用户</a><i></i></li>
            <li><cite></cite><a href="logout.do" target="rightFrame">退出登录</a><i></i></li>
        </ul>
    </dd>
</dl>
</body>
</html>

创建用户退出登录的servlet

package com.zj.web.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 javax.servlet.http.HttpSession;
import java.io.IOException;
/*用户退出*/
@WebServlet("/logout.do")
public class LogoutServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //因为配置了监听器,在session销毁的时候会调用监听器的方法,删除context中的session
        session.invalidate();
        //重定向到登录页面
        resp.sendRedirect("login.jsp");
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

七、添加用户业务

7.1 创建添加用户持久层

创建接口和实现类

package com.zj.dao;
import com.zj.pojo.User;
public interface UserManageDao {
    //用户添加
    void insertUser(User user);
}
package com.zj.dao.impl;
import com.zj.commons.jdbcUtils;
import com.zj.dao.UserManageDao;
import com.zj.pojo.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class UserManageDaoImpl implements UserManageDao {
    @Override
    public void insertUser(User user) {
        Connection con = null;
        try {
            con = jdbcUtils.getConnection();
            //关闭自动提交事务,加深对事务印象
            con.setAutoCommit(false);
            PreparedStatement ps = con.prepareStatement("INSERT INTO users values (default ,?,?,?,?,?)");
            ps.setString(1, user.getUsername());
            ps.setString(2, user.getUserpwd());
            ps.setString(3, user.getUsersex());
            ps.setString(4, user.getPhonenumber());
            ps.setString(5, user.getQqnumber());
            ps.executeUpdate();
            con.commit();
        }catch (Exception e) {
            e.printStackTrace();
            //出现异常回滚
            jdbcUtils.rollbackConnection(con);
        }finally {
           jdbcUtils.closeConnection(con);
        }
    }
}

7.2 创建添加用户业务层

创建添加用户的接口和实现类

package com.zj.service;
import com.zj.pojo.User;
public interface UserManageService {
    void addUser(User user);
}
package com.zj.service.Impl;
import com.zj.dao.UserManageDao;
import com.zj.dao.impl.UserManageDaoImpl;
import com.zj.pojo.User;
import com.zj.service.UserManageService;
public class UserManageServiceImpl implements UserManageService {
    /*添加用户*/
    @Override
    public void addUser(User user) {
        UserManageDao userManageDao = new UserManageDaoImpl();
        userManageDao.insertUser(user);
    }
}

7.3 创建添加用户servlet

package com.zj.web.servlet;
import com.zj.pojo.User;
import com.zj.service.Impl.UserManageServiceImpl;
import com.zj.service.UserManageService;
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("/userManage.do")
public class UserManageServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String flag = req.getParameter("flag");
        if ("add".equals(flag)) {
                addUser(req, resp);
        }
    }
    //添加用户
    private void addUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        User user = this.createUser(request, response);
        try {
         UserManageService userManagerService = new UserManageServiceImpl();
         userManagerService.addUser(user);
         response.sendRedirect("ok.jsp"); //重定向防止数据重复提交
        }catch (Exception e) {
            e.printStackTrace();
            response.sendRedirect("error.jsp");
        }
    }
    //获取用户提交的数据
    private User createUser(HttpServletRequest request,HttpServletResponse response){
        String username = request.getParameter("username");
        String userpwd = request.getParameter("userpwd");
        String usersex = request.getParameter("usersex");
        String phonenumber = request.getParameter("phonenumber");
        String qqnumber = request.getParameter("qqnumber");
        User user = new User(0,username, userpwd, usersex, phonenumber, qqnumber);
        return user;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

7.4 创建添加用户页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>无标题文档</title>
    <link href="../css/style.css" rel="stylesheet" type="text/css" />
    <link href="../css/style.css" rel="stylesheet" type="text/css" />
    <link href="../css/select.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="../js/jquery.js"></script>
    <script type="text/javascript" src="../js/jquery.idTabs.min.js"></script>
    <script type="text/javascript" src="../js/select-ui.min.js"></script>
    <script type="text/javascript" src="editor/kindeditor.js"></script>
    <script type="text/javascript" src="My97DatePicker/WdatePicker.js"></script>
    <script type="text/javascript">
        $(document).ready(function(e) {
            $(".select1").uedSelect({
                width : 345
            });
        });
        function save(){
            window.location='ok.html';
        }
    </script>
    <script type="text/javascript">
        KE.show({id:"ecp",width:"800px",height:"300px"});
    </script>
</head>
<body>
<div class="place">
    <span>位置:</span>
    <ul class="placeul">
        <li><a href="#">用户管理</a></li>
        <li><a href="#">添加用户</a></li>
    </ul>
</div>
<div class="formbody">
    <div class="formtitle"><span>添加用户</span></div>
    <form action="../userManage.do" method="post">
        <%--当前是添加用户信息--%>
   <input type="hidden" name="flag" value="add"/>
    <ul class="forminfo">
        <li>
            <label>用户名</label>
            <input name="username" type="text" class="dfinput" /></li>
        <li>
        <li>
            <label>用户密码</label>
            <input name="userpwd" type="text" class="dfinput" /><i></i></li>
        <li>
            <label>性别</label>
            <input name="usersex" type="radio" value="1" checked="checked" />男&nbsp;&nbsp;&nbsp;&nbsp;
            <input name="usersex" type="radio" value="0" />女
        </li>
        <li>
            <label>联系方式</label>
            <input name="phonenumber" type="text" class="dfinput" />
        </li>
        <li>
            <label>QQ号</label>
            <input name="qqnumber" type="text" class="dfinput" />
        </li>
        <li>
            <label>&nbsp;</label>
            <input  type="submit"  class="btn" value="确认保存" />
        </li>
    </ul>
    </form>
</div>
</body>
</html>

创建添加成功的页面ok.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <link href="css/style.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript">
        function submitForm(){
            window.close();
        }
    </script>
</head>
<body>
<div class="place">
    <span>位置:</span>
    <ul class="placeul">
        <li><a href="#">操作提示</a></li>
    </ul>
</div>
操作成功!
</body>
</html>


相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
21天前
|
设计模式 安全 Java
Java并发编程实战:使用synchronized关键字实现线程安全
【4月更文挑战第6天】Java中的`synchronized`关键字用于处理多线程并发,确保共享资源的线程安全。它可以修饰方法或代码块,实现互斥访问。当用于方法时,锁定对象实例或类对象;用于代码块时,锁定指定对象。过度使用可能导致性能问题,应注意避免锁持有时间过长、死锁,并考虑使用`java.util.concurrent`包中的高级工具。正确理解和使用`synchronized`是编写线程安全程序的关键。
|
4天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
24 0
|
2天前
|
消息中间件 缓存 NoSQL
Java多线程实战-CompletableFuture异步编程优化查询接口响应速度
Java多线程实战-CompletableFuture异步编程优化查询接口响应速度
|
3天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
8天前
|
IDE Java 数据库连接
使用 Java 进行桌面应用开发
【4月更文挑战第19天】Java 是一款广泛应用于企业级、网络和桌面应用开发的编程语言。其跨平台特性使Java程序能在不同操作系统上运行,而JDK提供了开发所需工具和库。使用Swing等GUI库构建用户界面,结合JDBC进行数据库操作,Socket实现网络通信。虽然面临性能和用户体验的挑战,但通过优化和选用合适的IDE,Java仍能开发出高效稳定的桌面应用。
|
8天前
|
存储 Java 数据库连接
java DDD 领域驱动设计思想的概念与实战
【4月更文挑战第19天】在Java开发中,领域驱动设计(Domain-Driven Design, DDD) 是一种软件设计方法论,强调以领域模型为中心的软件开发。这种方法通过丰富的领域模型来捕捉业务领域的复杂性,并通过软件满足核心业务需求。领域驱动设计不仅是一种技术策略,而且还是一种与业务专家紧密合作的思维方式
31 2
|
9天前
|
前端开发 Java Go
开发语言详解(python、java、Go(Golong)。。。。)
开发语言详解(python、java、Go(Golong)。。。。)
|
9天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
151 10
|
9天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
16天前
|
运维 NoSQL 算法
Java开发-深入理解Redis Cluster的工作原理
综上所述,Redis Cluster通过数据分片、节点发现、主从复制、数据迁移、故障检测和客户端路由等机制,实现了一个分布式的、高可用的Redis解决方案。它允许数据分布在多个节点上,提供了自动故障转移和读写分离的功能,适用于需要大规模、高性能、高可用性的应用场景。
16 0