项目场景:
使用jsp+servlet实现简单的注册登录功能,以及文件格式检测功能。
开发过程:
项目创建
-
选择java工程
-
选择javaSDK版本和tomcat版本(根据自己电脑上的版本进行选择)
-
web Application版本选择(版本跟我不一样也没事,问题不大)
-
目录结构
-
服务器首次启动
下图为浏览器显示效果
通过url地址,我们发现实际访问的是index.jsp页面
这说明,服务器启动的时候,默认访问的就是index.jsp文件事实证明,确实如此。浏览器显示的,确实是我们index.jsp中写的内容
MVC编程模式
在讲功能实现的时候,先介绍一下什么叫作MVC
MVC是Move,View,Controller的缩写,代表了三种责任
- Move表示模型:用于存储数据,以及处理用户的业务逻辑
- View表示视图:用于向控制器提交数据,然后显示模型中的数据
- Controller表示控制器:用于接收视图发过来的请求,然后从数据交给模型,讲处理完后的视图发给视图
基于 Servlet 的 MVC 模式的具体实现如下。
-
模型:一个或多个 JavaBean 对象,用于存储数据(实体模型,由 JavaBean 类创建)和处理业务逻辑(业务模型,由一般的
Java 类创建)。 -
视图:一个或多个 JSP 页面,向控制器提交数据和为模型提供数据显示,JSP 页面主要使用 HTML 标记和 JavaBean
标记来显示数据。 -
控制器:一个或多个 Servlet 对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的
详细点的话,我们项目的架构就是下图这样
登录注册功能
思考一下,要怎么实现登录功能呢?
-
第一步,要打开登录页面的网页,然后输入账号密码
-
第二步,当我们点击登录以后,html页面要把我们输入的信息发给服务器
-
第三步,服务器将前端页面传来的用户数据,在数据库中查找
-
第四步,如果数据库中刚好有前端传来的用户数据,那就让登录成功实现
那要怎么实现注册呢
- 第一步,打开注册页面,然后输入要注册的用户名和密码
- 第二步,点击注册之后,html将我们的注册信息交给后台服务器处理
- 第三步,将注册的信息存入数据库
下面让我们来实现这些流程
1 首先要创建一个用户表
这里设置id为自增
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(32) NOT NULL,
`email` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
)
先给数据库添加条测试数据
2 构造三层架构
根据我们的架构图,创建出三层架构
- dao层:持久层,用来跟数据库进行交互
- service层:调用持久层,用来处理业务逻辑
- web层:视图层,用来调用service层,同时获取请求参数,封装成Bean
把自己的包目录创建出来
然后创建三层架构所属的包
我们首先在dao层中创建一个userDao接口,用来编写登录和注册的方法
现在返回类型User报红,这是因为我们还没有写相应的Bean对象,所以我们需要再创建一个pojo包,存放我们的Pojo对象
我们创建的UserBean如下
package com.pan.project.pojo;
public class User {
private int id;
private String username;
private String password;
private String email;
public User() {
}
//因为id是自动生成的,所以我们在赋值的时候,不用指定id
public User(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
}
User类对应的是我们创建出来的数据表
Pojo类是用来存储数据的载体,User这个类就是user这个表生成的一个实体类
现在回到我们的dao包中,看看我们的UserDao接口
这时候User已经不报红了
登录的方法写好我们再写一个注册的方法
package com.pan.project.dao;
import com.pan.project.pojo.User;
public interface UserDao {
/**
* 根据用户名和密码查询用户信息
* @param username 用户名
* @param password 密码
* @return
*/
//我们要将查询结果,封装成一个User Bean对象
User findUser(String username, String password);
/**
* 用来存放用户信息
* @param user
* @return
*/
int save(User user);
}
接口写完之后,我们就要写这个接口的实现类
现在只是重写了两个方法,方法里的内容还没有写。
那要写什么内容呢?
在前面说过,我们dao层是负责与数据库交互的。
所以我们需要在dao层的实现类中做到与数据库连接并进行交互。
数据库连接
1.先写数据库连接的配置文件
username=root //你数据库的用户名
password=root //你数据库的密码
url=jdbc:mysql://localhost:3306/book?serverTimezone=GMT%2B8//book是我的数据库名,到时候要写你自己的
driverClassName=com.mysql.cj.jdbc.Driver
initialSize=5
maxActive=10
此外我们还需要两个jar包,也就是上图jar中的包
- druid:数据库连接池
- mysql-connector-java-8.0 :是MySQL提供的JDBC驱动包,用JDBC连接MySQL数据库时必须使用该jar包
我们现在创建的lib并不能让idea知道这是一个lib包,所以我们需要赋给它权限
一旦将它赋于权限之后,它就是真正的lib包了。包下的jar就会自动解压
连接数据库前的准备做好之后,我么现在就开始写代码进行连接了。
创建一个工具类进行数据库的连接。
package com.pan.project.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtil {
private static DataSource ds;//创建连接池
static {
try{
//获取配置文件
Properties properties = new Properties();
InputStream t = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(t);
//初始化连接池对象
ds = DruidDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnect() throws SQLException {
//获取数据库连接Connection对象
return ds.getConnection();
}
}
工具类创建好之后,我们来测试一下,这个工具类是否真能获取连接
往lib包中,丢一个junit的jar包,就可以使用注解@Test进行测试了
package com.pan.project.test;
import com.pan.project.util.JdbcUtil;
import org.junit.Test;
import java.sql.Connection;
import java.sql.SQLException;
public class test {
@Test //Test注解 用来指名这是一个测试方法
public void textGetConnect(){
try {
Connection connection = JdbcUtil.getConnect();
System.out.println(connection);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
说明我的连接能成功获取
既然能成功连接数据库之后,那我们就开始完成登录和注册功能吧。
我们先简单改一下index.jsp的页面
接下来先实现一下注册页面的功能
注册
我们需要准备一个注册的页面
页面做成什么样都无所谓,做的简陋点也没有关系。
重要的是代码结构中的表单部分
因为我们前端的数据要通过form表单将数据传递给后端
所以我们需要在表单中写上,用户名,密码,邮箱等多个input标签,同时需要给每个标签的name值进行设置,这些值要和数据库中user表的字段相同。
这时候我们发现上图中多了个学号的属性,那我们可以改一下数据库中的user表,加上一个stuno字段。
同时把User的内容也改一下,加了成员变量studo和它的getter和setter操作
package com.pan.project.pojo;
public class User {
private int id;
private String username;
private String password;
private String email;
private String stuno;
public User() {
}
public User(String username, String password, String email, String stuno) {
this.username = username;
this.password = password;
this.email = email;
this.stuno = stuno;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
", stuno='" + stuno + '\'' +
'}';
}
}
根据下面这张图,我们知道,前端页面是要将请求发给Servlet的,所以我们现在创建一个Servlet,就叫LoginServlet吧
由于我在doGet方法中调用了doPost方法,所以不管form表单发来的是get还是post请求,都会在doPost方法中进行处理。
下面我们开始写doPost方法中的逻辑
package com.pan.project.web;
import com.pan.project.dao.UserDao;
import com.pan.project.dao.impl.UserDaoImpl;
import com.pan.project.pojo.User;
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("/LoginServlet") //LoginServlet的路径,通过这个路径就能访问到这个LoginServlet
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实例化一个UserDaoImpl对象
UserDao userDao = new UserDaoImpl();
//获取前端页面传来的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String stuno = req.getParameter("stuno");
//上面这些参数的名字,要与你前端input标签中的name相同
//将数据封装到User中
User user = new User(username,password,email,stuno);
//因为我们userDao中写了存储User的方法,所以现在我们拿出用一下
if(userDao.save(user)!=0){
//表示注册成功,我们就返回登录页面
resp.getWriter().print("<script>alert(\"注册成功!\");</script>");
resp.sendRedirect("index.jsp");
}else{
//失败则进行提示
resp.getWriter().print("<script>alert(\"注册失败!\");</script>");
}
}
}
这里面有用到之前我们写的UserDaoImpl中的save()方法,现在我们对这个方法内容进行编写
package com.pan.project.dao.impl;
import com.pan.project.dao.UserDao;
import com.pan.project.pojo.User;
import com.pan.project.util.JdbcUtil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class UserDaoImpl implements UserDao {
@Override
public User findUser(String username, String password) {
return null;
}
@Override
public int save(User user) {
try {
//获取连接
Connection connection = JdbcUtil.getConnect();
//注册,就是说,要将数据插入数据库表中
String sql = "insert into user(username,password,email,stuno) values(?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给各个属性填充值
preparedStatement.setString(1,user.getUsername());
preparedStatement.setString(2,user.getPassword());
preparedStatement.setString(3,user.getEmail());
preparedStatement.setString(4,user.getStuno());
//执行sql update语句
return preparedStatement.executeUpdate(); //返回这个表示注册成功
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return 0; //返回这个表示注册失败
}
}
到这里,注册功能就算完成了,我们来试着操作一下
首先到注册页面写入数据
然后点击提交
注册成功就会返回主页面,其实你们也可以设置成,注册成功返回登录页面
然后我们来看一下数据库中是否有数据
我们发现表中最后一行记录,就是我们刚刚注册的数据。
虽然注册功能成功实现了,但是我们想想,还有地方需要注意呢?
没错,就是当我们注册的时候,后端还需要判断,这个用户是不是已经存在了。
不存在,我们才能往数据表中存数据,如果存在,那么就应该提示用户。
所以修改一下我们的LoginServlet代码
package com.pan.project.web;
import com.pan.project.dao.UserDao;
import com.pan.project.dao.impl.UserDaoImpl;
import com.pan.project.pojo.User;
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("/LoginServlet") //LoginServlet的路径,通过这个路径就能访问到这个LoginServlet
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//防止乱码
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
//实例化一个UserDaoImpl对象
UserDao userDao = new UserDaoImpl();
//获取前端页面传来的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String stuno = req.getParameter("stuno");
//上面这些参数的名字,要与你前端input标签中的name相同
//将数据封装到User中
User user = new User(username,password,email,stuno);
//如果找到的记录不为空,则表示要查找的用户已存在
User other = new User();
other = userDao.findOneByName(username);
//用户存在,或者两个用户的学号相等
if(other!=null){
if(other.getStuno().equals(user.getStuno())){
resp.getWriter().print("<script>alert(\"学号已存在!\");</script>");
//返回到注册那一页
resp.getWriter().print("<script>history.go(-1);</script>");
}else{
resp.getWriter().print("<script>alert(\"用户已存在!\");</script>");
//返回到注册那一页
resp.getWriter().print("<script>history.go(-1);</script>");
}
}else{
//因为我们userDao中写了存储User的方法,所以现在我们拿出用一下
userDao.save(user);
//表示注册成功,我们就返回登录页面
resp.getWriter().print("<script>alert('登录成功!')</script>");
resp.getWriter().print("<script>window.location.href='index.jsp';</script>");
}
}
}
主要是靠在UserDao中新增了一个findOneByName来实现。
在UserDao中新增一个抽象方法
然后到UserDaoImpl中去重写这个方法
package com.pan.project.dao.impl;
import com.pan.project.dao.UserDao;
import com.pan.project.pojo.User;
import com.pan.project.util.JdbcUtil;
import java.sql.*;
public class UserDaoImpl implements UserDao {
@Override
public User findUser(String username, String password) {
return null;
}
@Override
public int save(User user) {
try {
//获取连接
Connection connection = JdbcUtil.getConnect();
//注册,就是说,要将数据插入数据库表中
String sql = "insert into user(username,password,email,stuno) values(?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给各个属性填充值
preparedStatement.setString(1,user.getUsername());
preparedStatement.setString(2,user.getPassword());
preparedStatement.setString(3,user.getEmail());
preparedStatement.setString(4,user.getStuno());
//执行sql update语句
return preparedStatement.executeUpdate(); //返回这个表示注册成功
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return 0; //返回这个表示注册失败
}
@Override
public User findOneByName(String username) {
//获取连接
try {
Connection connection = JdbcUtil.getConnect();
String sql = "select * from user where username = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//给?填充值
preparedStatement.setString(1,username);
ResultSet resultSet = preparedStatement.executeQuery();
User user = new User();
if (resultSet.next()){
//resultSet.next() 为true则表示能从表中找到相关记录
user.setUsername(resultSet.getString("username"));
user.setUsername(resultSet.getString("password"));
user.setStuno(resultSet.getString("stuno"));
//返回已经封装好数据的user
return user;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
}
这样就能解决重复用户的问题了。
到此为止注册部分的代码就完成了。
(未完待续…)