JavaWeb开发实战(一)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: JavaWeb开发实战(一)

一、业务需求

实现用户登录和退出登录功能,要求一个用户只在一处登录。完成对用户表的CRUD操作。

主要以消化技术为主。

二、技术栈

JSP、Servlet、Filter、Listener、JDBC、MySQL

三、创建数据库表

CREATE TABLE `users` (
 `userid` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(30) DEFAULT NULL,
 `userpwd` varchar(30) DEFAULT NULL,
 `usersex` varchar(2) DEFAULT NULL,
 `phonenumber` varchar(30) DEFAULT NULL,
 `qqnumber` varchar(20) DEFAULT NULL,
 PRIMARY KEY (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

四、搭建环境

4.1 创建web项目

4.2 添加jar

用到数据库:MySQL驱动的jar

用到servlet:servlet-api.jar

页面中中使用jstl标签库:jstl标签库jar包

4.3 添加jstl标签库的约束文件

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

五、创建项目包以及工具类

5.1 创建项目包

5.2 创建POJO

package com.zj.pojo;
public class User {
    private int userid;
    private String username;
    private String userpwd;
    private String usersex;
    private String phonenumber;
    private String qqnumber;
    public User() {
    }
    public User(int userid, String username, String userpwd, String usersex, String phonenumber, String qqnumber) {
        this.userid = userid;
        this.username = username;
        this.userpwd = userpwd;
        this.usersex = usersex;
        this.phonenumber = phonenumber;
        this.qqnumber = qqnumber;
    }
    public int getUserid() {
        return userid;
    }
    public void setUserid(int userid) {
        this.userid = userid;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getUserpwd() {
        return userpwd;
    }
    public void setUserpwd(String userpwd) {
        this.userpwd = userpwd;
    }
    public String getUsersex() {
        return usersex;
    }
    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }
    public String getPhonenumber() {
        return phonenumber;
    }
    public void setPhonenumber(String phonenumber) {
        this.phonenumber = phonenumber;
    }
    public String getQqnumber() {
        return qqnumber;
    }
    public void setQqnumber(String qqnumber) {
        this.qqnumber = qqnumber;
    }
    @Override
    public String toString() {
        return "User{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", userpwd='" + userpwd + '\'' +
                ", usersex='" + usersex + '\'' +
                ", phonenumber='" + phonenumber + '\'' +
                ", qqnumber='" + qqnumber + '\'' +
                '}';
    }
}

5.3 创建JDBC工具类

在src下创建db.properties属性文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=123456
package com.zj.commons;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ResourceBundle;
public class jdbcUtils {
    private static String driver;
    private static String url;
    private static String username;
    private static String password;
    //初始化数据库驱动,读取db.properties配置文件的信息(static中的资源只会加载一次)
    static {
        ResourceBundle resourceBundle = ResourceBundle.getBundle("db");
        driver = resourceBundle.getString("jdbc.driver");
        url = resourceBundle.getString("jdbc.url");
        username = resourceBundle.getString("jdbc.username");
        password = resourceBundle.getString("jdbc.password");
        //加载数据库驱动
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection(){
        Connection con = null;
        try {
        con = DriverManager.getConnection(url, username, password);
        }catch (Exception e){
          e.printStackTrace();
        }
        return con;
    }
    //关闭连接
    public static void closeConnection(Connection con){
        try {
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    //事务回滚
    public static void rollbackConnection(Connection con) {
        try {
            con.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

六、用户登录业务的实现

6.1 创建登录页面

将样式文件先复制到web目录下。

在web目录下创建login.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 src="js/cloud.js" type="text/javascript"></script>
    <script language="javascript">
        if (window.parent.length>0){
            window.parent.location = "login.jsp";
        }
        $(function(){
            $('.loginbox').css({'position':'absolute','left':($(window).width
                ()-692)/2});
            $(window).resize(function(){
                $('.loginbox').css({'position':'absolute','left':($(window).width
                    ()-692)/2});
            })
        });
        /*点击验证码图片生成验证码*/
        function change() {
           $("#code").attr("src","ValidateCodeServlet.do?"+Math.random())
        }
    </script>
</head>
<body style="background-color:#1c77ac;
background-image:url(images/light.png);
background-repeat:no-repeat; background-position:center top;
        overflow:hidden;">
<div id="mainBody">
    <div id="cloud1" class="cloud"></div>
    <div id="cloud2" class="cloud"></div>
</div>
<div class="logintop">
    <ul>
        <li><a href="#">回首页</a></li>
        <li><a href="#">帮助</a></li>
        <li><a href="#">关于</a></li>
    </ul>
</div>
<div class="loginbody">
    ${requestScope.msg}
    <div class="loginbox loginbox2">
        <form action="login.do" method="post">
            <ul>
                <li><input name="username" type="text" class="loginuser" value="admin" onclick="JavaScript:this.value=''"/></li>
                <li><input name="userpwd" type="password" class="loginpwd" value="" onclick="JavaScript:this.value=''"/></li>
                <li class="yzm">
                    <span><input name="code" type="text" value="验证码" onclick="JavaScript:this.value=''"/></span><cite><img id="code" src="ValidateCodeServlet.do" onclick="change()"/></cite>
                </li>
                <li><input name="" type="submit" class="loginbtn" value="登录" onclick="javascript:window.location='main.html'"/></li>
            </ul>
        </form>
    </div>
</div>
</body>
</html>

 

6.2 创建登录业务的持久层

在Dao包下创建UserLoginDao接口,在接口中创建抽象方法selectUserByUserNameAndPassword。

package com.zj.dao;
import com.zj.pojo.User;
public interface UserLoginDao {
    public User selectUserByUserNameAndPassword(String userName, String password);
}

创建UserLoginDao接口的实现类UserLoginDaoImpl实现接口。

package com.zj.dao.impl;
import com.zj.commons.jdbcUtils;
import com.zj.dao.UserLoginDao;
import com.zj.pojo.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserLoginDaoImpl implements UserLoginDao {
    /*用户登录实现*/
    @Override
    public User selectUserByUserNameAndPassword(String userName, String password) {
        User user = null;
        Connection conn = null;
        try {
            conn = jdbcUtils.getConnection();
            PreparedStatement ps = conn.prepareStatement("select * from users where username = ? and userpwd = ?");
            ps.setString(1, userName);
            ps.setString(2, password);
            ResultSet resultSet = ps.executeQuery();
            while (resultSet.next()) {
                user = new User();
                user.setUsername(resultSet.getString("username"));
                user.setUserpwd(resultSet.getString("userpwd"));
                user.setUsersex(resultSet.getString("usersex"));
                user.setPhonenumber(resultSet.getString("phonenumber"));
                user.setQqnumber(resultSet.getString("qqnumber"));
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
        return user;
    }
}

6.3 登录业务的业务层

在Service包下创建UserLoginService接口,在接口中创建抽象方法userLogin。

package com.zj.service;
import com.zj.pojo.User;
public interface UserLoginService {
    public User userLogin(String username, String password);
}

创建UserLoginService接口的实现类UserLoginServiceImpl实现接口。

package com.zj.service.Impl;
import com.zj.dao.UserLoginDao;
import com.zj.dao.impl.UserLoginDaoImpl;
import com.zj.exception.UserNotFoundException;
import com.zj.pojo.User;
import com.zj.service.UserLoginService;
/*用户登录业务*/
public class UserLoginServiceImpl implements UserLoginService {
    @Override
    public User userLogin(String username, String password) {
        //创建持久层对象
        UserLoginDao userLoginDao = new UserLoginDaoImpl();
        User user = userLoginDao.selectUserByUserNameAndPassword(username, password);
        if (user == null) {
           throw new UserNotFoundException("用户名或密码有误!");
        }
        return user;
    }
}

同时创建异常类UserNotFoundException,当没有查到用户的信息的时候抛出异常,要继承RuntimeException 。

package com.zj.exception;
/*用户登录状态的自定义异常*/
public class UserNotFoundException extends RuntimeException {
   public UserNotFoundException(){
    }
   public UserNotFoundException(String message) {
    }
   public UserNotFoundException(String message, Throwable cause) {
    }
}

6.4 创建登录业务的web层

在servlet包下创建UserLoginServlet 。

package com.zj.web.servlet;
import com.zj.commons.Constants;
import com.zj.exception.UserNotFoundException;
import com.zj.pojo.User;
import com.zj.service.Impl.UserLoginServiceImpl;
import com.zj.service.UserLoginService;
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("/login.do")
public class UserLoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        try {
            UserLoginService userLoginService = new UserLoginServiceImpl();
            User user = userLoginService.userLogin(username, password);
            //如果存在user,建立客户端和服务端的会话状态。
            HttpSession session = req.getSession();
            session.setAttribute(Constants.USER_SESSION_KEY,user);
            //使用重定向跳转到首页,因为可以改变地址栏的地址
            resp.sendRedirect("main.jsp");
        }catch (UserNotFoundException e) {//这是我们关心的异常
            //用户登陆失败跳转到登录页面
            req.setAttribute("msg",e.getMessage());
            req.getRequestDispatcher("login.jsp").forward(req,resp);
        }catch (Exception e) { //处理异常的最后一道防线,处理其他异常
            //出现其他错误
            resp.sendRedirect("error.jsp");
        }
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

在工具包创建Constants 抽象类(不能被实例化)存放常量。

package com.zj.commons;
/*常量抽象类,避免字符串硬编码。不允许被实例化*/
public abstract class Constants {
    public static String USER_SESSION_KEY = "user";
}

在web目录下创建main.jsp,作为登录成功跳转的页面。其中main.jsp是由index.jsp、left.jsp、footer.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>
</head>
<frameset rows="*,31" cols="*" frameborder="no" border="0"
          framespacing="0">
    <frameset cols="187,*" frameborder="no" border="0"
              framespacing="0">
        <frame src="left.jsp" name="leftFrame" scrolling="No"
               noresize="noresize" id="leftFrame" title="leftFrame" />
        <frame src="index.jsp" name="rightFrame" id="rightFrame"
               title="rightFrame" />
    </frameset>
    <frame src="footer.jsp" name="bottomFrame" scrolling="No"
           noresize="noresize" id="bottomFrame" title="bottomFrame" />
</frameset>
<noframes><body>
</body></noframes>
</html>
</html>

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1天前
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
19 5
|
1天前
|
前端开发 Java 数据库连接
【潜意识Java】深度解读JavaWeb开发在Java学习中的重要性
深度解读JavaWeb开发在Java学习中的重要性
18 4
|
1天前
|
SQL Java API
|
1天前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
10 2
|
13天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
15天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
71 17
|
26天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
11天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
28天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
28天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。