需求: 利用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();}//封装一条记录到JavaBeanuser.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;@Overridepublic 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
{@Testpublic void testMySaveUser(){MySql model = new MySql();User user = new User("aa", "aa", "aa", "bb");int saveUserToXml = model.saveUserToXml(user);System.out.println(saveUserToXml);}@Testpublic void testMyFindUser(){MySql model = new MySql();boolean ret = model.findUserNameInXml("aa", "bb");// 断言Assert.assertEquals(false, ret);}@Testpublic void testMyFindUsername(){MySql model = new MySql();boolean ret = model.findUserNameInXml("cc");Assert.assertEquals(true, ret);}}
“