大一萌新又来写博客啦~
大一上学期结束时 老师给我们布置了基于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).