我的第一个JavaWeb项目-基于servlet的在线教材管理系统Part1——设计与注册部分

大一萌新又来写博客啦~
大一上学期结束时 老师给我们布置了基于c语言的课程实验设计 《教材管理系统》
要求:

之后学了《在线博客系统》后,灵稽一动,决定自己写个在线教材管理系统。
技术栈:maven、mysql(8.x)、servlet(3.1)

功能介绍:
用户分类:用户分为普通用户和管理员用户。普通用户可以查看、借阅与归还书籍。管理员可以增加新的书籍或者删除书籍。
1注册界面:分为管理员注册和普通用户注册,管理员账号注册需要输入内置的验证码进行简单的校验。
2登陆页面:分为管理员登陆和普通用户登陆,管理员也可以作为普通用户进行登录。但是普通用户不能通过管理员登录界面进行登录。

数据库设计:

drop database if exists TeachingManagement;
create database if not exists TeachingManagement;
use TeachingManagement;
create table user
(
    userId   int primary key auto_increment,
    userName varchar(50) unique,
    passWord varchar(50),
    isAdmin  bit
);
create table books
(
    bookId     int primary key auto_increment,
    bookName   varchar(50),
    author     varchar(50),
    remarks    varchar(100),
    userid     int default null,
    isBorrowed bit default 0,
    body       mediumtext
);

用户属性:用户id、用户名、密码、isAdmin表示用户是否为管理员。其中用户id通过主键自动增长。
书籍属性:书籍id、书籍名、作者、备注、(借阅了这本书的)用户id(默认为null),isBorrowed表示这本书是否被借出、body表示书籍正文。 其中书籍id通过主键自动增长。

然后在mysql中构建数据库和表单即可。
之后就是具体实现了。
项目整体结构如下:
在这里插入图片描述

先配置pom.xml中的dependencies

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

实现普通用户登录界面html
效果:
在这里插入图片描述

代码:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
          name="viewport">
    <meta content="ie=edge" http-equiv="X-UA-Compatible">
    <title>注册用户</title>
</head>
<body>
<div style="color:red;text-align:center">
    <h1>此页面仅供学习交流使用,请勿输入常用的账户密码!</h1>
</div>
<h1 style="color:blue;text-align:center">教材管理系统</h1>
<div style="text-align:center">
    <h3>普通用户注册页面</h3>
</div>

<form action="registerUser" method="post" style="text-align:center">
    <div style="height: 10px">
        <input name="name" placeholder="请输入用户名" type="text">
    </div>
    <br/>
    <div style="height: 10px">
        <input name="password" placeholder="请输入密码" type="password">
    </div>
    <br/>
    <input type="submit" value="注册">
    <br/>
</form>
<div style="text-align:center">
    <a href="registerAdmin.html">管理员注册</a>
    <br>
    <a href="login.html">已有账号,前往登陆</a>
</div>

</body>
</html>

web.xml配置:

    <servlet>
        <servlet-name>register</servlet-name>
        <servlet-class>api.registerUser</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>register</servlet-name>
        <url-pattern>/registerUser</url-pattern>
    </servlet-mapping>

此时在api.registerUser处理请求

public class registerUser extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset = utf-8");
        String username = req.getParameter("name");
        String password = req.getParameter("password");
        Writer writer = resp.getWriter();
        String html = null;
        if (UserDao.selectUserByName(username) != null) {
            html = HttpGenerator.getByMessage("用户名重复!请重新注册", "register.html");
        } else {
            User user = new User();
            user.setUserName(username);
            user.setPassWord(password);
            user.setAdmin(false);
            UserDao.addUser(user);
            html = HttpGenerator.getByMessage("注册成功!请登录", "login.html");
        }
        writer.write(html);
    }
}

从req中获取提交的name和password 然后
通过调用UserDao静态方法获取一个User类。
其中UserDao负责处理数据层逻辑
代码如下:


    public static User selectUser(String name, String password) {
        Connection connection = dbUtil.getConnection();
        PreparedStatement statement = null;
        String sql = "select * from user where userName = ? and passWord = ?";
        User user = null;
        ResultSet resultSet = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1, name);
            statement.setString(2, password);
            resultSet = statement.executeQuery();
            //当 ResultSet 为非空时,其游标指向第一条记录前面,若为空时由于不存在第一条记录,所以这时候游标也无法向指第一条记录前面
            if (!resultSet.isBeforeFirst()) {
                System.out.println("查找不到用户");
                return null;
            }
            if (resultSet.next()) {
                user = new User(resultSet.getString("userName"),
                        resultSet.getString("passWord"),
                        resultSet.getInt("userId"),
                        resultSet.getBoolean("isAdmin"));
            }
            System.out.println(user);

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            dbUtil.close(connection, statement, resultSet);
        }
        return user;
    }

获取Connection连接后,构建SQL语句,注意返回的resultset不会为null,所以不要用if(resultSet==null)来判断是否查询到了用户。这里百度了个isBeforeFirst()方法,
解释为:当 ResultSet 为非空时,其游标指向第一条记录前面,若为空时由于不存在第一条记录,所以这时候游标也无法向指第一条记录前面,此时该方法返回false;

通过resultSet获取字段构建一个User类并返回。

注意到这里用了dbUtil 下面介绍此处功能和实现。
dbUtil管理数据库连接。
代码如下:

public class dbUtil {
    private static final String url = "jdbc:mysql://127.0.0.1:3306/TeachingManagement?characterEncoding=utf-8&useSSL=true";
    private static final String userName = "root";
    private static final String password = "xxxxx";
    private static DataSource dataSource = null;

    public static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (dbUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource) dataSource).setURL(url);
                    ((MysqlDataSource) dataSource).setUser(userName);
                    ((MysqlDataSource) dataSource).setPassword(password);
                }
            }
        }
        return dataSource;
    }

    //获取连接
    public static Connection getConnection() {
        try {
            Connection connection = getDataSource().getConnection();
            return connection;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return null;
    }

    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

考虑到事务的原子性,这里给DataSource加了锁

 if (dataSource == null) {
            synchronized (dbUtil.class) {
                if (dataSource == null) 

这样,其他逻辑就可以调用dbUtil的静态方法直接获取连接。
连接使用完后,应当关闭连接 应当关闭三者:
Connection, PreparedStatement 和 ResultSet
注意判断三者为null的情况

回归正题登陆部分:
这里写了一些脑瘫方法用于生成html的字符串

比如这个简单的消息界面

    public static String getByMessage(String message, String url) {
        StringBuilder str = new StringBuilder();
        str.append("<html>");
        str.append("<head>");
        str.append("<meta charset=\"UTF-8\">");
        str.append("<title>提示页面</title>");
        str.append("</head>");
        str.append("<body>");
        str.append("<h3>");
        str.append(message);
        str.append("</h3>");
        str.append(String.format("<a href=\"%s\">点击跳转</a>", url));
        str.append("</body>");
        str.append("</html>");

        return str.toString();
    }

比如 如果提交了一个已经有的用户数据,则通过

if (UserDao.selectUserByName(username) != null) {
html = HttpGenerator.getByMessage(“用户名重复!请重新注册”, “register.html”);

构建了以下页面
在这里插入图片描述
点击跳转后返回/register.html
在这里插入图片描述
如果注册成功 则返回登陆成功的消息
在这里插入图片描述

代码为

        } else {
            User user = new User();
            user.setUserName(username);
            user.setPassWord(password);
            user.setAdmin(false);
            UserDao.addUser(user);
            html = HttpGenerator.getByMessage("注册成功!请登录", "login.html");
        }

点击后跳转到登陆界面(太丑了勿喷)
在这里插入图片描述

之后是管理员的注册

这里有个不太好的地方,只做了 管理员校验码的检验 没有做用户重复的检验,会造成数据库中的复写。
先上web.xml配置

    <servlet>
        <servlet-name>registerAdmin</servlet-name>
        <servlet-class>api.registerAdmin</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>registerAdmin</servlet-name>
        <url-pattern>/registerAdmin</url-pattern>
    </servlet-mapping>

然后是逻辑处理的代码

public class registerAdmin extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        String identity = req.getParameter("identity");
        resp.setContentType("text/html; charset = utf-8");
        Writer writer = resp.getWriter();
        if (!identity.equals("666")) {
            writer.write(HttpGenerator.getByMessage("身份校验码错误,无法注册管理员账号!(测试验证码为666)", "adminLogin.html"));
            return;
        }
        User user = new User();
        user.setUserName(name);
        user.setPassWord(password);
        user.setAdmin(true);
        UserDao.addUser(user);
        writer.write(HttpGenerator.getByMessage("管理员注册成功!请前往登陆", "loginAdmin.html"));


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

注册成功后 返回登陆提示
在这里插入图片描述

然后是把User类加入数据库数据
普通用户和管理员均使用同一个方法,只是isAdmin字段不同

    public static void addUser(User user) {
        Connection connection = dbUtil.getConnection();
        String sql = "insert into user values(null,?,?,?)";
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(sql);
            statement.setString(1, user.getUserName());
            statement.setString(2, user.getPassWord());
            statement.setBoolean(3, user.isAdmin());
            int ret = statement.executeUpdate();
            if (ret != 1) {
                System.out.println("插入新用户失败");
                return;
            }
            System.out.println("插入新用户成功!");
            System.out.println(user);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            dbUtil.close(connection, statement, null);
        }
    }

记得务必在最后关闭数据库连接

} finally {
            dbUtil.close(connection, statement, null);
        }

好了,以上就是注册部分的代码和逻辑实现。
下一篇Part2写登陆部分和用户身份校验(通过Session).

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值