JavaWeb开发实战(二)

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: 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>


相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
7天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
18 4
|
8天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
29 4
|
8天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
14 0
|
8天前
|
Java API Android开发
kotlin和java开发优缺点
kotlin和java开发优缺点
22 0
WK
|
14天前
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
27 0
|
6天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
15天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
3天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
16 9
|
6天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
3天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin