需求: 利用MVC模式实现网站注册登录模块
- (1)实现一个注册页面,可以将用户使用表单提交的注册信息保存到MySql数据库中,用户可以上传头像
- (2)实现一个登陆页面,当用户输入用户名和密码之后.去之前保存数据库里看看是否有该用户信息,如果有,就提示登陆成功,显示用户头像和用户名.没有的话,提示用户名密码错误,重新登陆
- (3)登录成功的用户可以通过注销退出登录
(一)注册界面前后端
1.注册界面JSP
- 需要实现前端对注册信息的验证,需要实现上传头像的功能
register.jsp
<form enctype="multipart/form-data" method="post" action="${pageContext.request.contextPath}/servlet/RegisterServlet" onsubmit="return validate()">
<table border="1" width="600">
<tr>
<td>*用户名:</td>
<td><input type="text" name="username" /> </td>
</tr>
<tr>
<td>*密码:</td>
<td><input type="password" name="password" /> </td>
</tr>
<tr>
<td>*确认密码:</td>
<td><input type="password" name="repass" /> </td>
</tr>
<tr>
<td>*Email:</td>
<td><input type="text" name="email" /> </td>
</tr>
<tr>
<td>*头像:</td>
<td><input type="file" name="headimg" /> </td>
</tr>
<tr>
<td><input type="submit" value="提交注册信息" /></td>
<td></td>
</tr>
</table>
</form>
前端Js验证:
function validate()
{
var name = document.getElementById("name");
var email = document.getElementById("email");
var password = document.getElementById("password");
var repass = document.getElementById("repass");
//判断姓名格式
var regName = /^([\u4e00-\u9fa5]+|([a-z]+\s?)+)$/;
if(name.value.match(regName) == null){
alert("姓名格式有误,请输入中文名或英文名!");
return false;
}
//判断电子邮箱格式
var regEmail=/^\w+@\w+\.(com|edu|org|gov|cn)$/g ;
if(email.value.match(regEmail)==null){
alert("电子邮箱格式错误!");
return false;
}
//判断密码
var regPassword =/(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{3,8}/
if(password.value.length<3||password.value.length>8)
{
alert("请设置长度位3~8的密码!");
return false;
}
else if(password.value.match(regPassword)==null)
{
alert("密码必须包含字符、数字和特殊字符!");
return false;
}
//验证确认密码
if(repss.value != password.value)
{
alert("确认密码不一致!");
return false;
}
return true;
}
2.注册控制器RegisterServlet
业务逻辑:
(1)对拿到的客户端请求数据进行验证和保存,切割表单数据和文件数据(函数一)
(2)验证通过,显示注册成功,跳到登陆界面,服务器端验证不通过,则回到注册界面,比如用户名已注册(函数二)
(3)把实现功能的函数封装进service中,把获取到的表单用户数据保存到数据库中
RegisterServlet.java
UserService service = new UserService();
private String uploadImgDirString;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
System.out.println("开始验证");
request.setCharacterEncoding("utf-8");//请求编码
response.setContentType("text/html;charset=utf-8");//告诉浏览器编码格式
response.setCharacterEncoding("utf-8");//正文编码
//common切割表单数据和文件
User user = parseUser(request);
//判断用户名是否已经注册过
boolean isUserNameExists = service.isUserNameExists(user.getUsername());
if (!isUserNameExists)
{
//没有重名,先保存用户数据到数据库中,然后跳转到登陆界面
int result = service.registerUser(user);
System.out.println("result="+result);
if (result==1)
{
response.getWriter().println("注册成功,1s后跳转到登陆界面");
response.setHeader("refresh","1;url='"+request.getContextPath()+"/login.jsp'");
}
}
else
{
response.getWriter().println("此用户名已被注册,请重新注册");
response.setHeader("refresh","1;url='"+request.getContextPath()+"/register.jsp'");
}
}
//解析数据包方法不可分离出去
private User parseUser(HttpServletRequest request)
{
//利用common-bin组件来解析数据包,拿到表单数据和图片地址
User user = new User();
String username = null;
String password = null;
String email = null;
String heading_path = null;
//拿到存放上传图像的路径
uploadImgDirString = request.getRealPath("/img");
//System.out.println("uploadImgDirString=" + uploadImgDirString);
//开始解析数据包
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletContext servletContext=this.getServletConfig().getServletContext();
File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
factory.setRepository(repository);
// 拿到上传组件
ServletFileUpload upload = new ServletFileUpload(factory);
// 开始解析请求的数据包
try
{
List<FileItem> filelist = upload.parseRequest(request);
// 处理apache已经分割好的数据集合
Iterator<FileItem> iter = filelist.iterator();
while (iter.hasNext())
{
FileItem item = iter.next();
if (item.isFormField())
{
// 如果是表表单数据
if (item.getFieldName().equals("username"))
{
username = item.getString();
}
else if (item.getFieldName().equals("password"))
{
password = item.getString();
}
else if (item.getFieldName().equals("email"))
{
email = item.getString();
}
}
else
{
// 如果是文件数据,交给service处理,接收返回的图片路径
heading_path=service.getFilePath(item, uploadImgDirString);
}
}
}
catch (FileUploadException e)
{
e.printStackTrace();
}
//封装一条记录到JavaBean
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
user.setHeading_path(heading_path);
return user;
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doGet(request, response);
}
3.JavaBean和Mysql数据库
- 包含username,password,email和图片路径heading_path
- 数据库需要新建并加载配置数据
User.java
public class User
{
private String username;
private String email;
private String password;
private String heading_path;
@Override
public String toString()
{
return "User [username=" + username + ", email=" + email
+ ", password=" + password + ", heading_path=" + heading_path
+ "]";
}
public User(String username, String email, String password,
String heading_path)
{
super();
this.username = username;
this.email = email;
this.password = password;
this.heading_path = heading_path;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getHeading_path()
{
return heading_path;
}
public void setHeading_path(String heading_path)
{
this.heading_path = heading_path;
}
}
DBUtils.java
package com.cskaoyan.db.utils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
//数据仓库
public class DBUtils
{
static Properties properties;
static Connection con;
static String host;
static String port;
static String db;
static
{
try
{
//加载配置文件
Class.forName("com.mysql.jdbc.Driver").newInstance();
String path = DBUtils.class.getClassLoader().getResource("conn.prop").getPath();
properties = new Properties();
properties.load(new FileInputStream(path));
host = properties.getProperty("host");
port = properties.getProperty("port");
db = properties.getProperty("db");
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
catch (InstantiationException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
//连接数据库
public static Connection getConnection() throws SQLException
{
String url = "jdbc:mysql://" + host + ":" + port + "/" + db;
return DriverManager.getConnection(url, properties);
}
//关闭连接,释放资源
public static void realeseResourse(Connection con, Statement st,
ResultSet rs)
{
if (con != null)
{
try
{
con.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (st != null)
{
try
{
con.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (rs != null)
{
try
{
con.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
}
数据库配置conn.prop放在src目录下
host=localhost
port=3306
db=mysj
user=root
password=123456
4.数据接口访问层
- 封装不同类型的数据库存取方法,比如将数据存入mysql数据库中,或者将数据存入xml文件中打印输出
需要不同的方法来实现
package com.cskaoyan.dataInterface;
import com.cskaoyan.model.User;
public interface UserData
{
//用戶数据访问接口,由具体的数据存储仓库去实现
public boolean findUserNameInXml(String username);
public int saveUserToXml(User user);
public boolean findUserNameInXml(String username, String password);
public String findHeadingPathInXml(String username);
}
5.写model实现对数据库的增删改查来保存user信息
- 需要实现数据接口层的具体方法
MySql.java
package com.cskaoyan.model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.cskaoyan.dataInterface.UserData;
import com.cskaoyan.db.utils.DBUtils;
//实现对具体类型的数据仓库的操作
public class MySql implements UserData
{
//判断注册用户名是否已经存在
public boolean findUserNameInXml(String username)
{
boolean ret = false;
Connection conn = null;
ResultSet rs = null;
PreparedStatement st = null;
try
{
conn = DBUtils.getConnection();
st = conn.prepareStatement("select * from user where username = ?;");
st.setString(1, username);
rs = st.executeQuery();
if (rs.next())
{// 结果集不为空,说明对应用户名和密码有
ret = true;
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return ret;
}
//把用户信息记录插入到数据库中
public int saveUserToXml(User user)
{
int ret = -1;
Connection conn = null;
ResultSet rs = null;
PreparedStatement st = null;
try
{
conn = DBUtils.getConnection();
st = conn.prepareStatement("insert into user values(?,?,?,?); ");
st.setString(1, user.getUsername());
st.setString(2, user.getPassword());
st.setString(3, user.getEmail());
st.setString(4, user.getHeading_path());
ret = st.executeUpdate();
}
catch (SQLException e)
{
e.printStackTrace();
}
return ret;
}
}
6.写service封装对数据库的具体操作(多态)
UserService.java
package com.cskaoyan.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
import org.apache.commons.fileupload.FileItem;
import com.cskaoyan.dataInterface.UserData;
import com.cskaoyan.model.MySql;
import com.cskaoyan.model.User;
//service层,实现业务逻辑,分派业务给具体的数据仓库去实现
public class UserService
{
//判读注册用户名是否存在
public boolean isUserNameExists(String username)
{
UserData userData = new MySql();
boolean isExists = userData.findUserNameInXml(username);
return isExists;
}
//保存用户信息到数据库中
public int registerUser(User user)
{
UserData userData = new MySql();
userData.saveUserToXml(user);
return 1;
}
public String getPicturePath(String username)
{
UserData userData = new MySql();
String picturePath = userData.findHeadingPathInXml(username);
return picturePath;
}
//处理文件数据,得到图片路径
public String getFilePath(FileItem item, String uploadImgDirString)
{
//拼接获取图片的绝对路径
String ret = null;
String fileName = item.getName(); // 文件名
try
{
InputStream inputStream = item.getInputStream();
// UUID文件重名的问题
UUID randomUUID = UUID.randomUUID();
String finalImageFilename = randomUUID.toString() + fileName;
// 文件目录规划的问题
// 在指定文件夹下创建一个新的文件
File file = new File(uploadImgDirString, finalImageFilename);
FileOutputStream fos = new FileOutputStream(file);
//输出流保存图片到服务器硬盘的指定位置
byte[] b = new byte[1024];
int len = 0;
while ((len = inputStream.read(b)) != -1)
{
fos.write(b, 0, len);
}
fos.close();
ret = file.getAbsolutePath();
}
catch (IOException e)
{
e.printStackTrace();
}
return ret;
}
}
(二)登陆界面前后端
1.写注册成功后跳转到的登陆界面JSP
login.jsp
<form action="${pageContext.request.contextPath}/servlet/LoginServlet" method="get">
用户名 <input type="text" name="username" /><br>
密 码 <input type="password" name="password" /><br>
<input type="submit" value="登录" />
</form>
2.写处理登录成功的servlet控制器
- 需要把用户登陆的用户名,密码保存到session中,通服务器后台数据库中的数据进行验证
- 需要利用得到的用户名去数据库中查找保存的图片路径,取出来保存到session中
- 以上两个方法的实现需要到service中写
LoginServlet.java
package com.cskaoyan.servlet;
public class LoginServlet extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
//验证用户名密码是否与服务器上一致
response.setContentType("text/html;charset=utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
UserService service = new UserService();
//找到图片路径
String path = service.getPicturePath(username);
//验证用户名和密码与数据库已保存的注册信息是否一致
boolean flag = service.checkUserInfo(username, password);
if (flag)
{
// 把用户信息和图片路径放到Session里
HttpSession session = request.getSession(true);
session.setAttribute("username", username);
session.setAttribute("password", password);
session.setAttribute("heading_path", path);
response.getWriter().println("登陆成功,即将跳转到主页");
response.setHeader("refresh", "1;url='" + request.getContextPath() + "/index.jsp'");
}
else
{
response.getWriter().println("用户名密码输入错误,请重新登陆");
response.setHeader("refresh", "1;url='"+request.getContextPath()+"/login.jsp'");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doGet(request, response);
}
}
3.写登陆界面的service和数据访问接口
- //验证用户名密码是否与服务器上一致
- //找到图片路径
UserService.java
public String getPicturePath(String username)
{
UserData userData = new MySql();
String picturePath = userData.findHeadingPathInXml(username);
return picturePath;
}
public boolean checkUserInfo(String username, String password)
{
UserData userData = new MySql();
boolean isUserInfOk = userData.findUserNameInXml(username, password);
return isUserInfOk;
}
MySql.java
public boolean findUserNameInXml(String username, String password)
{
boolean ret = false;
Connection conn = null;
ResultSet rs = null;
PreparedStatement st = null;
try
{
conn = DBUtils.getConnection();
st = conn.prepareStatement("select * from user where username = ? and password =? ; ");
st.setString(1, username);
st.setString(2, password);
rs = st.executeQuery();
if (rs.next())
{
ret = true; // 结果集不为空,说明存在对应用户名
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return ret;
}
public String findHeadingPathInXml(String username)
{
String headimg_path = null;
Connection conn = null;
ResultSet rs = null;
PreparedStatement ps;
try
{
conn = DBUtils.getConnection();
ps = conn.prepareStatement("select * from user where username = ?;");
System.out.println(username);
ps.setString(1, username);
rs = ps.executeQuery();
//查
while (rs.next())
{
headimg_path = rs.getString("headimg_path");
}
}
catch (SQLException e)
{
e.printStackTrace();
}
return headimg_path;
}
(三)写登陆成功的主页
1.登陆成功的界面JSP
- 需要显示用户图像和用户名
- 需要有注销按钮
<body>
<h1>个人主页</h1> <br>
<hr>
<%
response.setContentType("text/html;charset=utf-8");
String username = (String) pageContext.getAttribute("username", PageContext.SESSION_SCOPE);
String headPath = (String) pageContext.getAttribute("heading_path", PageContext.SESSION_SCOPE);
if (username ==null)
{
%>
<a href = "${pageContext.request.contextPath}/login.jsp">登录 </a>
<a href = "${pageContext.request.contextPath }/register.jsp">注册</a>
<%
}
else
{
%>
<img src='<%=headPath%>'/>
${username}, 欢迎您!<br>
<a href = '${pageContext.request.contextPath}/servlet/LogoutServlet'>注销</a>
<%
}
%>
</body>
2.注销Servlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/html;charset=utf-8");
HttpSession session = request.getSession(false);
if (session != null)
{
session.invalidate();
response.getWriter().println("正在注销,1秒后跳转到主页");
response.setHeader("refresh", "1;url='"+request.getContextPath()+"/index.jsp'");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doGet(request, response);
}
(四)利用Junit测试各函数是否正常运行
package com.cskaoyan.test;
import junit.framework.Assert;
import org.junit.Test;
import com.cskaoyan.model.MySql;
import com.cskaoyan.model.User;
@SuppressWarnings("deprecation")
public class FunctionTest
{
@Test
public void testMySaveUser()
{
MySql model = new MySql();
User user = new User("aa", "aa", "aa", "bb");
int saveUserToXml = model.saveUserToXml(user);
System.out.println(saveUserToXml);
}
@Test
public void testMyFindUser()
{
MySql model = new MySql();
boolean ret = model.findUserNameInXml("aa", "bb");
// 断言
Assert.assertEquals(false, ret);
}
@Test
public void testMyFindUsername()
{
MySql model = new MySql();
boolean ret = model.findUserNameInXml("cc");
Assert.assertEquals(true, ret);
}
}
“