JavaWeb-13 (用户的注册和登录案例)

JavaWeb-13:项目案例

用户注册和登录案例项目

一、用户注册和登录案例

1、技术架构:三层架构(表现层MVC:M:model V:View C:Controller)

JavaWeb-13 (用户的注册和登录案例)_第1张图片

2、要求:JSP中不能出现一行java脚本或java表达式。除了指令<%@%>,其余地方不能有<%%>

3、数据库:临时使用xml。解析使用Dom4j

4、必须知道要干什么?

5、开发步骤:

a、建立工程,搭建开发环境(拷贝jar包、建立配置文件)
    dom4j.jar
    jaxen.jar

    commons-beanutils.jar
    commons-logging.jar

    standard.jar
    jstl.jar

b、建立类所用的包

    cn.itcast.domain:放JavaBean    弄出数据库
    cn.itcast.dao:放Dao接口
    cn.itcast.dao.impl:放Dao接口的实现
    cn.itcast.servcie:业务接口
    cn.itcast.service.impl:业务接口实现
    cn.itcast.web.controller:Servlet控制器
    //WEB-INF/pages:用户无法直接访问(只能靠转发)

工程架构:

JavaWeb-13 (用户的注册和登录案例)_第2张图片

JavaWeb-13 (用户的注册和登录案例)_第3张图片

知识点:用户输入数据的验证

1、客户端验证:使用js代码。减轻服务器的负担
2、服务器端验证:使用java代码。安全
3、实际开发中:1+2

二、用户的注册和登录案例攻略

JavaWeb-13 (用户的注册和登录案例)_第4张图片JavaWeb-13 (用户的注册和登录案例)_第5张图片

1、搭建环境:

创建好需要用来读取和存储的xml数据库文件--->导入jar包(用来操作xml数据库文件的Dom4J包、封装数据用的BeanUtils包、使用XPath的jaxen-1.1-beta-6.jar包),创建User类(JavaBean),用于关联每一层的数据。

User.java

package com.heima.bean;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable{

    private String username ;

    private String password ;

    private String email ;

    private Date birthday ;

    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 Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

2、设计业务逻辑层和数据访问层的接口

新建dao包:

接口类IUserDao:新建用于操作JavaBean数据的方法接口类IUserDao,里面提供添加用户并返回用户对象的方法addUser接口,提供根据用户的名字和密码查找用户,返回用户对象的方法findUserByUserNameAndPassword接口,提供根据用户的姓名查找用户的方法findUserByUserName接口。

IUserDao

package com.heima.dao;

import com.heima.bean.User;

public interface IUserDao {

    /**
     * 将用户添加到数据库
     * @param user  要添加的用户
     * @return  成功返回此用户,失败返回null
     */
    public User addUser(User user) ;

    /**
     * 根据用户的名字和密码查找用户
     * param username  用户名
     * param password  用户的密码
     * @return 找到用户返回此用户,否则返回null
     */
    public User findUserByUserNameAndPassword(String username,String password ) ;

    /**
     * 根据用户的姓名查找用户
     * @param username 用户的姓名
     * @return 找到用户返回此用户,否则返回null
     */
    public User findUserByUserName(String username) ;

}

新建Utils包:

DBUtils类:该工具类主要用于获取xml里的数据和把数据写回xml文件的方法:

getDocument()和write2xml()方法。该类里使用了dom4J包里的工具类,例如创建dom4j解析器和写回xml文件的方法。

DBUtils.java

package com.heima.utils;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

//工具类
public class DBUtils {

    public static String path ;

    static{
        path = DBUtils.class.getClassLoader().getResource("users.xml").getPath() ;
    }

    //加载dom树
    public static  Document getDocument(){
        try {
            //创建dom4j解析器
            SAXReader reader = new SAXReader() ;
            //读取文档
            Document document = reader.read(path) ;
            return document ;
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null ;
    }

    //将内存中的dom树写回到硬盘
    public static void write2xml(Document document){
        try {
            XMLWriter writer = new XMLWriter(new FileOutputStream(path),OutputFormat.createPrettyPrint()) ;
            writer.write(document) ;
            writer.close() ;
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

新建dao.impl包:

该包用于存储继承接口类IUserDao的实现类UserDaoImpl.java。该类的作用:

addUser()主要是通过调用Utils包里提供的方法getDocument()和write2xml(),把从别处生成的User对象里的属性数据写到xml文件里并返回该User对象,findUserByUserNameAndPassword()主要是通过Utils包工具加载到xml里,然后通过dom4j里的方法使用XPath和相对应的属性定位到要找的user对象,并判断如果存在就封装成user对象并返回,无就返回null。

findUserByUserName()主要是通过传进来的属性并加载了xml文档后去使用XPath定位要找的user,如果不存在就返回一个新的User对象,若找到就返回null。

UserDaoImpl.java

package com.heima.dao.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;

import com.heima.bean.User;
import com.heima.dao.IUserDao;
import com.heima.utils.DBUtils;

public class UserDaoImpl implements IUserDao {

    public User addUser(User user) {
        //获取dom树
        Document document = DBUtils.getDocument() ;
        //获得根节点
        Element root = document.getRootElement() ;
        //添加用户
        root.addElement("user").addAttribute("username", user.getUsername())
            .addAttribute("password", user.getPassword())
            .addAttribute("email", user.getEmail())
            .addAttribute("birthday", new SimpleDateFormat("yyyy-MM-dd").format(user.getBirthday())) ;

        //写回硬盘
        DBUtils.write2xml(document) ;
        return user;
    }

    public User findUserByUserNameAndPassword(String username, String password) {
        //加载dom树
        Document document = DBUtils.getDocument() ;
        //查找user节点
        Node node = document.selectSingleNode("//user[@username='" + username + "' and @password='" + password+ "']") ;
        if(node != null){
            //封装数据
            User user = new User() ;
            Element el = (Element)node ;
            user.setUsername(el.valueOf("@username")) ;
            user.setPassword(el.valueOf("@password")) ;
            user.setEmail(el.valueOf("@email")) ;
            try {
                user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(el.valueOf("@birthday"))) ;
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return user ;
        }
        return null;
    }

    public User findUserByUserName(String username) {
        //加载dom树
        Document document = DBUtils.getDocument() ;
        //查找user节点
        Node node = document.selectSingleNode("//user[@username='" + username + "']") ;
        if(node != null){
            return new User() ;
        }
        return null;
    }

}

新建service包:

接口IUserService类:

该类的框架目的主要是让实现类去调用实现类UserDaoImpl.java里的功能。方法接口login():目的为了让实现类根据用户的姓名和密码完成用户的登录,方法接口:register()目的为了让实现类完成注册用户的功能。

IUserService.java

package com.heima.service;

import com.heima.bean.User;
import com.heima.exception.UserExistException;

public interface IUserService {

    /**
     * 根据用户的姓名和密码完成用户的登录
     * @param username  用户的姓名
     * @param password  用户的密码
     * @return 登录成功返回此用户,失败返回null
     */
    public User login(String username,String password ) ;


    /**
     * 完成注册用户的功能
     * @param user 要注册的用户
     * @return  成功返回TRUE,失败返回FALSE
     * @throws UserExistException 如果用户存在抛出用户存在异常
     */
    public boolean register(User user) throws UserExistException;
}

新建exception包:

UserExistException.java:

用于提供给UserServiceImpl类抛出异常。

UserExistException.java

package com.heima.exception;

public class UserExistException extends Exception {

}

新建service.impl包:

UserServiceImpl类:

在类里创建UserDaoImpl的对象,并使用UserDaoImpl对象里的方法去获得对应的User对象。

        login():通过根据用户的姓名和密码来传入到UserDaoImpl对象的方法中去完成用户的登录,并返回User对象。

        register():通过根据用户的姓名来传入到UserDaoImpl对象的方法中去完成用户的注册验证,并返回boolean值。还有判断如果用户存在抛出异常。

UserServiceImpl.java

package com.heima.service.impl;

import com.heima.bean.User;
import com.heima.dao.IUserDao;
import com.heima.dao.impl.UserDaoImpl;
import com.heima.exception.UserExistException;
import com.heima.service.IUserService;

public class UserServiceImpl implements IUserService {

    IUserDao dao = new UserDaoImpl() ;

    public User login(String username, String password) {
        return dao.findUserByUserNameAndPassword(username, password);
    }

    public boolean register(User user) throws UserExistException {
        //验证用户是否已经存在了
        User u = dao.findUserByUserName(user.getUsername()) ;
        if(u != null){
            //说明此用户已经存在了,需要抛出异常
            throw new UserExistException() ;
        }
        User u1 = dao.addUser(user) ;
        return u1!=null ;
    }

}

设计业务逻辑层和数据访问层的接口并实现步骤完成。

3、搭建表现层并连接各层间的关系

首先实现页面:新建index.jsp,写用于注册的register.jsp的超链和用于登录的login.jsp的超链

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    

    My JSP 'index.jsp' starting page
    
    
        
    
    
    
  

  
      注册   登陆
  

新建web.formbean包:

创建UserBean.java类:

该javabean类用于封装页面的数据和验证数据用的。类里除了各种属性和设置属性的方法之外,还有一个用来验证数据的方法validate(),就是从别处传来的各种属性都需要符合该方法里的规格,付过不符合,方法会为属性里的Map集合存储用于传达给页面的验证信息,并该方法最后返回boolean值反映存储的属性数据是否正确。

UserBean.java

package com.heima.web.formbean;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;

//主要用来封装页面的数据,验证数据
public class UserBean {

    private String username ;

    private String password ;

    private String repassword ;

    private String email ;

    private String birthday ;

    private Map errors = new HashMap() ;

    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 getRepassword() {
        return repassword;
    }

    public void setRepassword(String repassword) {
        this.repassword = repassword;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public Map getErrors() {
        return errors;
    }

    //检测数据
    public boolean validate(){
        //检测用户名
        if(username == null || "".equals(username)){
            errors.put("username", "用户名不能为空") ;
        }else{
            if(username.length() < 3 || username.length() > 8){
                errors.put("username", "用户名长度不符合要求") ;
            }
        }

        //检测密码
        if(password == null || "".equals(password)){
            errors.put("password", "密码不能为空") ;
        }else{
            if(password.length() < 3 || password.length() > 8){
                errors.put("password", "密码长度不符合要求") ;
            }
        }

        //检测重复密码
        if(!repassword.equals(password)){
            errors.put("password", "两次密码不一致") ;
        }

        //检测邮箱
        String reg = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$" ;
        if(email == null || "".equals(email)){
            errors.put("email", "邮箱不能为空") ;
        }else{
            if(!email.matches(reg)){
                errors.put("email", "邮箱格式不正确") ;
            }
        }

        //检测出生日期
        if(birthday == null || "".equals(birthday)){
            errors.put("birthday", "出生日期不能为空") ;
        }else{
//          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
//          try {
//              sdf.parse(birthday) ;
//          } catch (ParseException e) {
//              errors.put("birthday", "日期格式不正确") ;
//          }
            DateLocaleConverter dlc = new DateLocaleConverter() ;
            try {
                dlc.convert(birthday) ;
            } catch (Exception e) {
                errors.put("birthday", "日期格式不正确") ;
            }
        }

        return  errors.isEmpty() ;
    } 
}

在原来的Utils包:

新建WebUtils类:

该工具类用于给页面传进来的UserBean类中的属性数据还有页面发来的request请求进行使用反射技术生产对象:因为传来的类对象本来不存在,所以使用反射机制来处理生成对象,并使用BeanUtils包里的超级方法populate()把UserBean对象和页面中的属性和属性值包装起来,并返回。

WebUtils.java

package com.heima.utils;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;

//为页面服务的工具类
public class WebUtils {

    public static  T  fillFormBean(Class clazz,HttpServletRequest reqeust){
        T t = null ;
        //创建对象
        try {
            t = clazz.newInstance() ;
            BeanUtils.populate(t, reqeust.getParameterMap()) ;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return t ;  
    }
}

新建web.controls包:

新建RegisterServlet.java类:

用于处理页面register.jsp传进来的UserBean数据,并通过调用UserBean里的验证数据方法validate()验证页面传进来的数据是否有效,无效会跳转回register.jsp页面,然后BeanUtils.copyProperties()用于将数据从userBean中拷贝到user对象中,为存储到xml文档中的必然步骤。最后调用UserServiceImpl类中的register()方法注册用户,成功跳转到login.jsp页面,失败跳转回register.jsp页面。另外一种可能,如果register()抛出了异常,那么RegisterServlet.java就给异常处理。

RegisterServlet.java

package com.heima.web.controls;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;

import com.heima.bean.User;
import com.heima.exception.UserExistException;
import com.heima.service.IUserService;
import com.heima.service.impl.UserServiceImpl;
import com.heima.utils.WebUtils;
import com.heima.web.formbean.UserBean;

//注册处理器
public class RegisterServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");


//      UserBean formuser = new UserBean() ;
//      try {
//          BeanUtils.populate(formuser, request.getParameterMap()) ;
//      } catch (IllegalAccessException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      } catch (InvocationTargetException e) {
//          // TODO Auto-generated catch block
//          e.printStackTrace();
//      }
        //接收页面数据,封装数据
         UserBean userform = WebUtils.fillFormBean(UserBean.class, request) ;

         //验证数据是否有效
         if(!userform.validate()){
             //没有通过
             request.setAttribute("userform", userform) ;
             request.getRequestDispatcher("/register.jsp").forward(request, response) ;
             return ;
         }


         //验证通过
         //将数据从userBean中拷贝到user对象中
         User user = new User() ;
         try {
             //注册时间转换器
            ConvertUtils.register(new DateLocaleConverter(), Date.class) ; 
            //拷贝数据
            BeanUtils.copyProperties(user, userform) ;
        } catch (Exception e) {
            e.printStackTrace();
        }

         //注册用户
         IUserService us = new UserServiceImpl() ;
         try {
            boolean flag = us.register(user) ;
            if(flag){
                //注册成功
                response.getWriter().write("恭喜,注册成功,2秒后转向登陆页面") ;
                response.setHeader("Refresh", "2;url=" + request.getContextPath() + "/login.jsp") ;
            }else{
                response.getWriter().write("注册失败,2秒后转注册页面") ;
                response.setHeader("Refresh", "2;url=" + request.getContextPath() + "/register.jsp") ;
            }
        } catch (UserExistException e) {
            //此用户已经注册过了
            userform.getErrors().put("username", "此用户名已经注册了,请更换一个") ;
            request.setAttribute("userform", userform) ;
            request.getRequestDispatcher("/register.jsp").forward(request, response) ;      
        }



    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

最后创建register.jsp:

    利用el表达式把存到UserBean里的属性值通过submit按钮发送到指定的RegisterServlet里,register.jsp也会通过el表达式返回UserBean里Map类型的errors信息。

register.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    

    My JSP 'register.jsp' starting page

    
    
        
    
    
    

  
    
  
        
${"用户名" } ${userform.errors.username }
${"密码" } ${userform.errors.password }
${"确认密码" }
${"邮箱" } ${userform.errors.email }
${"出生日期" } ${userform.errors.birthday }

还有其他类和jsp文件:如下:

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    

    My JSP 'register.jsp' starting page

    
    
        
    
    
    

  
    
  
        ${errorinfo }
        
${"用户名" } ${userform.errors.username }
${"密码" } ${userform.errors.password }

LoginServlet.java

package com.heima.web.controls;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.heima.bean.User;
import com.heima.service.IUserService;
import com.heima.service.impl.UserServiceImpl;
//实现登陆功能
public class LoginServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //拿取页面传递的数据
        String username = request.getParameter("username") ;
        String password = request.getParameter("password") ;

        //查找用户
        //创建service层对象
        IUserService us = new UserServiceImpl() ;
        User user = us.login(username, password) ;
        if(user != null){
            //登陆成功
            request.getSession().setAttribute("loginuser", user) ;
            response.getWriter().write("登陆成功,2秒后转向主页") ;
            response.setHeader("Refresh", "2;url="+ request.getContextPath() + "/main.jsp") ;
        }else{
            //登陆失败
            request.setAttribute("errorinfo", "用户名或者密码错误") ;
            request.getRequestDispatcher("/login.jsp").forward(request, response) ;
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

main.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>



  
    

    My JSP 'register.jsp' starting page

    
    
        
    
    
    

  
  
        ${loginuser.username },欢迎你
  

表现层完成。

三、总结

用户--->register.jsp--->输入信息------>提交到RegisterServlet里,RegisterServlet结合UserBean类、UserServiceImpl类给用户注册----->注册成功后:数据会转到User类里,并通过业务逻辑层和数据访问层的类和方法把User类里的数据存储到xml数据库中。可以发现,我们搭建这个项目是和用户的思维完全相反的。


资料下载

你可能感兴趣的:(JavaWeb)