殷-黑马旅游第1天V3


typora-copy-images-to: img

day01-黑马旅游

学习目标

-[ ] 了解项目的生命周期
-[ ] 能够完成用户注册案例
-[ ] 能够完成BaseServlet优化请求处理

第一章 项目生命周期【了解】

1.1 项目生命周期

​ 完整地开发一个java项目一般都会经历以下几个阶段:

  1. 项目立项:确定项目研发;
  2. 需求阶段:《需求说明书》—不涉及技术,只涉及业务;
  3. 概要设计阶段:《概要设计说明书》—涉及技术选型和数据库设计阶段;
  4. 详细设计阶段:《详细设计说明书》—涉及业务的细节点(伪代码);
  5. 编码阶段:coding阶段–单元测试–模块测试—联测(程序员在开发环境自己测试);
  6. 测试组测试:《测试报告》;
  7. 公测阶段:参与人员–程序员,测试人员,真实用户;
  8. 发布上线;
  9. 维护和二次开发…;

1.2 黑马旅游技术选型与环境

1.2.1 黑马旅游项目简介

​ 黑马旅游网是一个类似途牛网和携程网的旅游预订平台。在这个平台中,我们需要完成基本的用户模块相关的功能和旅游线路 产品相关的功能以及对旅游产品的收藏 等功能。

1.2.2 技术选型

​ 技术选型就是确定完成项目开发要使用到的技术。《黑马旅游》中使用到的技术如下:

技术版本说明
Servlet3.1.0处理客户端请求和响应,注解开发
BeanUtils1.8.3封装客户端请求的数据
Spring JdbcTemplate4.1.2JDBC工具类
C3P00.9数据库连接池技术
Jedis2.8java版的redis客户端实现
1.2.3 开发工具与环境

​ 在企业往往是一个团队开发一个项目,为了避免团队中因工具版本带来的问题。正式开发之前往往需要先统一开发环境,以下是《黑马旅游》项目开发过程中需要统一的环境说明。

工具版本说明
IDEA2017.3开发工具
JDK1.8java开发环境
Maven3.2.3项目管理工具
Redis2.8.9非关系型数据库
MySQL5.6数据库
1.2.4 开发模式

​ 黑马旅游采用前后端分离的模式进行开发。前端开发人员负责页面的编写及数据的渲染。后端开发人员负责提供API(接口)。前后端采用指定的API接口进行交互。

第二章 搭建项目环境

2.1 创建maven的web工程

​ 使用idea创建maven的web工程。并正确设置web项目的目录结构。

  1. 将项目的打包方式改为war;
  2. 设置正确的webapp目录,生成web.xml文件;

在这里插入图片描述

2.2 导入静态文件

​ 将“资料/01-静态页面”复制到项目的webapp目录下,如图:

在这里插入图片描述

2.3 创建包结构

​ 在src/main/java目录下,创建如下包结构:

在这里插入图片描述

com.heima.travel.common		存放通用代码
com.heima.travel.dao		jdbc相关
com.heima.travel.model		实体类
com.heima.travel.service	业务层
com.heima.travel.utils		工具类
com.heima.travel.web		web层

2.4 导入依赖

​ 在pom.xml文件中导入以下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.heima.maven.heima-travel</groupId>
    <artifactId>heima-travel</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
      <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <!--servlet-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.26</version>
            <scope>runtime</scope>
        </dependency>
        <!--beanutils-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.3</version>
        </dependency>
        <!--c3p0连接池-->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <!--jdbcTemplate-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.1.2.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.1.2.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>4.1.2.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.1.2.RELEASE</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
            <scope>compile</scope>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.46</version>
        </dependency>
        <!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.1</version>
        </dependency>
    </dependencies>
    
    <build>
      <!--maven构建项目所需的插件-->
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.0.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                  <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.20.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

2.5 导入配置文件

将“资料/配置文件”复制到resource资源目录中

在这里插入图片描述

修改c3p0-config.xml文件中的连接信息:修改数据库名,用户名和密码信息。

在这里插入图片描述

2.6 导入工具类

将“资料/工具类”复制到utils包中

在这里插入图片描述

2.7 导入数据库脚本

第一步:新建数据库

​ 打开数据库客户端工具Navicat,创建数据库heima_travel,并选择对应的字符集和排序规则。
在这里插入图片描述

第二步:执行数据库脚本

​ 在刚创建的数据库上点击右键—运行SQL文件。

在这里插入图片描述

​ 找到资料中的sql脚本,点击确定。sql脚本文件在今天的资料中。

在这里插入图片描述

表之间的关系如下图

在这里插入图片描述

2.8 导入实体类

将“资料/实体类”复制到model包中

在这里插入图片描述

2.9 导入其他公共类

将“资料/其他常用类”复制到common包中

在这里插入图片描述

2.10 配置tomcat

第一步:点击Edit Configurations

在这里插入图片描述

第二步:添加tomcat

在这里插入图片描述

第三步:修改tomcat名,添加依赖

在这里插入图片描述

第四步:点击Applay—OK

在这里插入图片描述

第五步:启动测试

在这里插入图片描述

第三章 案例-用户注册案例

​ 用户注册业务是将用户的数据录入到数据库中,录入前需要对用户录入的数据进行一系列合法性校验。用户数据录入成功之后,需要根据用户输入的邮箱地址发送邮件进行激活,激活成功之后才能正确登录。

3.1 用户注册

3.1.1 用户注册需求

​ 需求- 需求分析 -》代码

​ 用户注册,就是将用户在页面上输入的数插入到数据库中。但是,插入之前需要对用户提交的数据进行校验。校验分为前端校验和后端校验。完成用户注册业务要求如下:

  1. 注册数据处理:
    • 前端校验:数据完整性与合法性校验
    • 后台校验:数据唯一性校验
    • 数据处理:将数据插入到数据库
  2. 邮件激活:
    • 邮件发送:注册成功发送激活邮件
    • 激活:根据激活码激活
  3. 响应处理:
    • 注册数据添加成功:跳转到register_ok.html页面
    • 注册数据添加失败:在register.html页面显示错误提示信息

具体规则如下:

1. 前端校验:JS校验,validate插件校验;
   1. 用户名(非空);
   2. 密码(非空,长度在6到12位);
   3. 真实姓名(非空);
   4. email(非空,合法);
   5. 手机号(非空,合法);
   6. 验证码(非空);
   
2. email异步校验:email唯一性校验;

3. 验证码校验:校验用户输入的验证码是否正确;

4. 表单数据异步提交:以上校验均通过后,将表单数据异步提交到服务器,表单
   1. 密码MD5加密处理;
   2. 激活状态:默认未激活;
   3. 激活码:随机生成激活码;
   
5. 表单注册成功之后,发送激活邮件,并跳转到register_ok.html页面;注册失败,在注册页面给出错误提示信息;

3.1.2 需求分析

在这里插入图片描述

3.2 前端校验实现

【validate插件校验】

由于前端需要校验的字段比较多,我们使用jquery-validate.js插件,对页面数据进行校验。实现步骤如下:

  1. 导入jquery.validate.js文件。注意:放在jquery后面:

在这里插入图片描述

  1. 使用validate方法对表单中的字段进行校验:
/*
 *validate插件使用步骤:
 *1、导入jquery.js文件;
 *2、导入validate.js文件;
 *3、确定对哪个表单进行校验;调用validate方法
 *4、配置校验规则和错误提示信息;
*/

$("#registerForm").validate({
            //配置校验规则
            rules:{
                username:{
                    required:true
                },
                email:{
                    required:true,
                    email:true
                },
                telephone:{
                    phoneFmt:true
                }
            },
            //配置错误提示信息
            messages:{
                username:{
                    required:"用户名不能为空"
                },
                email:{
                    required:"email不能为空",
                    email:"请输入合法的email"
                }

            }
        });

​ 注意:telephone的校验采用了自定义校验规则telephone ,这个校验规则被单独写在common.js文件中。使用时需要在register.html文件中先导入common.js文件。以下是common.js文件的内容:

在这里插入图片描述

【commons.js文件】

//自定义校验规则:phoneFmt
/*
* 使用步骤:
*    $.validator.addMethod()
* */
/*
* $.validator(rulename,fn,msg)
* 1、 rulename:校验规则的名称
* 2、 fn:实现具体校验逻辑的方法
* 3、msg:设置校验不通过时的错误提示信息
* */
$.validator.addMethod("phoneFmt",function (value,element,param) {
    /*
    * 1、value:获取用户在被校验的标签中输入的value值;
    * 2、element:被校验的标签的对象
    * 3、param:使用校验规则时,传入的值
    * */
    //书写校验逻辑

    console.log(value+"  "+element+"   "+ param);
    if(param) {
        //对手机号合法性校验:正则
        //1、创建正则对象:
        /*
        * 方式一:              new RegExp(" 正则  ")
        * 方式二: 字面量       /正则表达式/
        * */
        // var phoneReg = new RegExp("^1[3456789]\\d{9}$");
        // var phoneCheckFlag = phoneReg.test(value);
        //
        // if(phoneCheckFlag){
        //     //手机号合法:return true
        //     return true;
        // }

        return new RegExp("^1[3456789]\\d{9}$").test(value);

    }

},"手机号不合法!");

3.3 用户email唯一性校验

​ email异步校验,对email输入框绑定onblur事件发送异步请求进行校验。

【前端实现】register.html

  1. 发送ajax请求进行异步校验:

在这里插入图片描述

【web层】CheckEmailServlet.java

package com.heima.travel.web;

import com.heima.travel.service.UserService;
import com.heima.travel.service.impl.UserServiceImpl;

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;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:14
 * @description 校验email的唯一性
 **/
@WebServlet("/checekEmailServlet")
public class ChecekEmailServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、接收请求数据
        String email = request.getParameter("email");

        //2、处理数据:拿email到数据库中查询数据
        UserService userService = new UserServiceImpl();
        //返回值:true:校验通过(从数据库中没有查到数据)     false
        boolean checkFlag = userService.checkEmail(email);

        //3、响应数据
        response.getWriter().println(checkFlag);
    }
}

【Service层】UserService.java

boolean regist(User user) throws Exception;   

【Service层】UserServiceImpl.java

 /**
     * 校验email的唯一性
     * @param email
     * @return
     */
    @Override
    public boolean checkEmail(String email) {

        //调用dao层  到数据库中查询数据
        List<User> userList =  userDao.queryByEmail(email);

        //userList != null  返回false
        if (null != userList && userList.size() > 0) {
            return  false;
        }

        return true;
    }

【Dao层】UserDao.java

package com.heima.travel.dao;

import com.heima.travel.model.User;

import java.util.List;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:21
 * @description TODO
 **/
public interface UserDao {
    List<User> queryByEmail(String email);

}

【Dao层】UserDaoImpl.java

package com.heima.travel.dao.impl;

import com.heima.travel.dao.UserDao;
import com.heima.travel.model.User;
import com.heima.travel.utils.C3p0Utils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:21
 * @description 处理用户模块CRUD的dao实现类
 **/
public class UserDaoImpl implements UserDao {

    //初始化模板
    private JdbcTemplate jdbcTemplate = new JdbcTemplate(C3p0Utils.getDataSource());


    @Override
    public List<User> queryByEmail(String email) {
        String sql = "SELECT * FROM tab_user WHERE email=?";
       return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class), email);
    }

}

【提交注册数据代码】

页面:

在这里插入图片描述

【web层】

package com.heima.travel.web;

import com.alibaba.fastjson.JSON;
import com.heima.travel.model.User;
import com.heima.travel.service.UserService;
import com.heima.travel.service.impl.UserServiceImpl;
import org.apache.commons.beanutils.BeanUtils;

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;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:55
 * @description 处理注册数据的提交
 **/
@WebServlet("/registServlet")
public class RegistServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        //1、接收请求数据
        //获取整个表单数据
        Map<String, String[]> map = request.getParameterMap();

        //使用BeanUtils工具类,把map中的数据 封装到实体类中
        User user = new User();
        //封装结果集的map
        Map<String, Object> result = new HashMap<>();
        try {
            BeanUtils.populate(user,map);
            //2、处理数据:把user中的数据插入到数据库中,调用service层处理
            UserService userService = new UserServiceImpl();

            //registFlag:   true--成功  false--失败
            boolean registFlag = userService.regist(user);

            result.put("checkFlag", registFlag);

        } catch (Exception e) {
            e.printStackTrace();
            result.put("checkFlag", false);
            result.put("msg", "注册出现异常,请联系管理员!");
        }

        //3、响应数据:json   {name:value} -- map<key,value>
        String s = JSON.toJSONString(result);
        response.getWriter().println(s);


    }
}

【service层】

 boolean regist(User user) throws Exception;
  /**
     * 提交注册数据
     * @param user
     * @return
     */
    @Override
    public boolean regist(User user) throws Exception {

        //处理注册数据:

        //1、设置激活状态为:0-未激活
        user.setStatus(0);
        //2、设置激活码
        user.setCode(UuidUtil.getUuid());

        //3、对密码加密处理
        //原始密码
        String password = user.getPassword();
        //加密
        String md5Pwd = Md5Util.encodeByMd5(password);
        user.setPassword(md5Pwd);

        //调用dao层插入数据
        int addNum = userDao.addUser(user);


        return addNum != 0;
    }

【dao层】

 int addUser(User user);
   /**
     * 数据录入
     * @param user
     * @return
     */
    @Override
    public int addUser(User user) {
        String sql = "INSERT INTO tab_user VALUES(NULL,?,?,?,?,?,?,?,?,?)";

        return jdbcTemplate.update(sql,
                user.getUsername(),
                user.getPassword(),
                user.getName(),
                user.getBirthday(),
                user.getSex(),
                user.getTelephone(),
                user.getEmail(),
                user.getStatus(),
                user.getCode());
    }

3.4 Servlet优化—BaseServlet

【请求分发思想】 Servlet请求优化一

  1. 用户业务相关的请求集中请求同一个servlet—UserServlet;
  2. 每个请求都携带一个methodName 字段,当请求进入UserServlet后,根据methodName 字段,将不同的请求传给不同的方法来处理;

在这里插入图片描述

【通过方法名动态调用方法】 Servlet优化二

​ 通过上面的请求分发发现,调用方法,我们只需要根据请求的方法名。调用这个方法即可,我们可以使用反射机制,根据方法名动态获取方法对象然后再进行调用即可。

在这里插入图片描述

【将方法抽取到BaseServlet中】 Servlet优化三

在这里插入图片描述

第一步:将请求分发抽取到BaseServlet中。

【BaseServlet.java】

package com.heima.travel.web;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/19 15:22
 * @description TODO
 **/
public class BaseServlet extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1、接收请求数据
        //获取url后面的methodName值
        String methodName = request.getParameter("methodName");

        //2、处理数据
//        if ("checkEmail".equals(methodName)) {
//            //处理email的唯一性校验
//            checkEmail(request,response);
//        } else if ("regist".equals(methodName)) {
//            //处理注册数据提交
//            regist(request,response);
//        } else if ("login".equals(methodName)) {
//            //用户登录处理
//        }

        //根据方法名调用方法:1、根据方法名动态获取方法;2、动态调用方法;  --- 反射
        try {
            //1、根据方法名动态获取方法
            Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            //2、动态调用方法;
            //取消权限检查
            method.setAccessible(true);
            method.invoke(this, request, response);

        } catch (Exception e) {
            e.printStackTrace();
        }

        //3、响应数据

    }
}

第二步:UserServlet继承BaseServlet

在这里插入图片描述

【改造email异步校验后台请求】

第一步:将请求的路径改为userServlet并在请求地址后面添加参数methodName=checkEmail

在这里插入图片描述

第二步:创建UserServlet删除doGet和doPost方法并继承BaseServlet,添加checkEmail方法。将CheckEmailServlet中的校验逻辑复制到checkEmail方法中:

package com.heima.travel.web;

import com.alibaba.fastjson.JSON;
import com.heima.travel.service.UserService;
import com.heima.travel.service.impl.UserServiceImpl;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@WebServlet(urlPatterns = "/userServlet")
public class UserServlet extends BaseServlet {
     private UserService userService = new UserServiceImpl();

    /**
     * 异步校验email的唯一性
     * @param request
     * @param response
     * @throws IOException
     */
    private void checkEmail(HttpServletRequest request, HttpServletResponse response)throws IOException {
//校验email的唯一性
        //1、获取请求数据
        String email = request.getParameter("email");
        //2、处理数据----从数据库中查询
        //checkEmailFlag == true:说明已存在数据   反之
        boolean checkEmailFlag = userService.checkeEmail(email);
        //3、响应数据
        Map<String, Object> result = new HashMap<>();
        result.put("checkEmailFlag", checkEmailFlag);
        //把map转换成JSON字符串
        String jsonString = JSON.toJSONString(result);
        response.getWriter().println(jsonString);
    }
}

3.5 注册数据异步提交

【前端实现】register.html

​ 监听表单的提交事件,当点击鼠标之后,异步提交表单数据。注意:需要将表单默认的提交事件阻止。

在这里插入图片描述

【web层】UserServlet.java

​ UserServlet中创建register方法处理请求数据。

  /**
     * 处理注册数据提交
     */
    private void regist(HttpServletRequest request, HttpServletResponse response) throws IOException {

        //1、接收请求数据
        //获取整个表单数据
        Map<String, String[]> map = request.getParameterMap();

        //使用BeanUtils工具类,把map中的数据 封装到实体类中
        User user = new User();
        //封装结果集的map
        Map<String, Object> result = new HashMap<>();

        try {
            BeanUtils.populate(user,map);
            //2、处理数据:把user中的数据插入到数据库中,调用service层处理

            //registFlag:   true--成功  false--失败
            boolean registFlag = userService.regist(user);

            //注册成功-给用户发送激活邮件
            if (registFlag) {
                //给用户发送激活邮件
                MailUtil.sendEmail(user.getEmail(),
                        "<h1>恭喜您,注册成功!</h1><a href='http://localhost:8080/userServlet?methodName=active&code="+user.getCode()+"'>请点击此链接,进行激活</a>");
            }

            result.put("checkFlag", registFlag);

        } catch (Exception e) {
            e.printStackTrace();
            result.put("checkFlag", false);
            result.put("msg", "注册出现异常,请联系管理员!");
        }

        //3、响应数据:json   {name:value} -- map<key,value>
        String s = JSON.toJSONString(result);
        response.getWriter().println(s);
    }

【service层】UserService.java

 boolean regist(User user) throws Exception;

【service层】UserServiceImpl.java

​ service层处理业务,主要业务有:

  • 添加注册表单的信息到数据库;
  • 密码加密处理;
  • 生成随机的激活码;
  /**
     * 提交注册数据
     * @param user
     * @return
     */
    @Override
    public boolean regist(User user) throws Exception {

        //处理注册数据:

        //1、设置激活状态为:0-未激活
        user.setStatus(0);
        //2、设置激活码
        user.setCode(UuidUtil.getUuid());

        //3、对密码加密处理
        //原始密码
        String password = user.getPassword();
        //加密
        String md5Pwd = Md5Util.encodeByMd5(password);
        user.setPassword(md5Pwd);

        //调用dao层插入数据
        int addNum = userDao.addUser(user);

        return addNum != 0;
    }

【dao层】UserDao.java

​ UserDao是处理用户持久化的接口;

    int addUser(User user);

【dao层】UserDaoImpl.java

​ UserDaoImpl中主要处理,UserDao接口的具体实现。

   /**
     * 数据录入
     * @param user
     * @return
     */
    @Override
    public int addUser(User user) {
        String sql = "INSERT INTO tab_user VALUES(NULL,?,?,?,?,?,?,?,?,?)";
        return jdbcTemplate.update(sql,
                user.getUsername(),
                user.getPassword(),
                user.getName(),
                user.getBirthday(),
                user.getSex(),
                user.getTelephone(),
                user.getEmail(),
                user.getStatus(),
                user.getCode());
    }

用户注册–添加用户完整代码

【前端】

【HTML】register.html

<script>
        //validate插件使用:基于jquery实现的插件
        /*
        * 1、导入jquery.js文件;(放在validate前面导入)
        * 2、导入validate.js文件;
        * 3、确定对页面上的哪个form表单进行校验:调用validate方法
        *       $("#form").validate();
        * 4、在validate()方法中配置:
        *       校验规则: rules
        *        错误提示信息:messages
        * */

        $("#registerForm").validate({
            //校验规则:
            rules:{
                //对用户名进行非空校验:标签的name属性值
                username:{
                    required:true
                },
                password:{
                    //非空:
                    required:true,
                    rangelength:[6,12]
                },
                email:{
                    required:true,
                    //email合法性校验
                    email:true,
                    remote:"/userServlet?methodName=checkEmail"
                },
                telephone:{
                    required:true,
                    //对手机号合法性校验
                    phoneFmt:true
                }

            },
            //错误提示信息
            messages:{
                username:{
                    required:"用户名不能为空!"
                },
                password:{
                    //非空:
                    required:"密码不能为空!",
                    rangelength:"密码长度必须在{0}到{1}位之间!"
                },
                email:{
                    required:"email不能为空!",
                    //email合法性校验
                    email:"email不合法!",
                    remote:"email已存在,请更换!"
                }

            },
            submitHandler:function (form) {
                //校验通过之后提交表单:异步提交-ajax
                //param:方式一  字符串 "name=value&name=value"  方式二:对象 {name:value,name:value}

                //jq的表单序列化: jq对象.serialize(); === "name=value&name=value"
                var formData = $(form).serialize();
                $.post("/userServlet?methodName=regist",formData,function (result) {
                    //处理响应数据:{checkFlag:true}
                    console.log(result);
                    if(result.checkFlag){
                        //注册成功: 跳转到register_ok.html
                        location.href = "/register_ok.html";
                    }else{
                        //注册失败: 在register.html给出错误提示信息
                        var errorMsg = result.msg;
                        $("#msg").html(errorMsg);
                    }

                    //  {name:value}
                },"json");
            }
        });
    </script>

【JavaScript】common.js

$.validator.addMethod("phoneFmt",function (value,element,param) {
    /*
    * 1、value:获取用户在被校验的标签中输入的value值;
    * 2、element:被校验的标签的对象
    * 3、param:使用校验规则时,传入的值
    * */
    //书写校验逻辑

    console.log(value+"  "+element+"   "+ param);
    if(param) {
        //对手机号合法性校验:正则
        //1、创建正则对象:
        /*
        * 方式一:              new RegExp(" 正则  ")
        * 方式二: 字面量       /正则表达式/
        * */
        // var phoneReg = new RegExp("^1[3456789]\\d{9}$");
        // var phoneCheckFlag = phoneReg.test(value);
        //
        // if(phoneCheckFlag){
        //     //手机号合法:return true
        //     return true;
        // }

        return new RegExp("^1[3456789]\\d{9}$").test(value);

    }

},"手机号不合法!");
【后台】

【web层】UserServlet.java

package com.heima.travel.web;

import com.alibaba.fastjson.JSON;
import com.heima.travel.model.User;
import com.heima.travel.service.UserService;
import com.heima.travel.service.impl.UserServiceImpl;
import com.heima.travel.utils.MailUtil;
import org.apache.commons.beanutils.BeanUtils;

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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/19 15:00
 * @description 处理用户模块请求和响应的Servlet
 **/
@WebServlet("/userServlet")
public class UserServlet extends BaseServlet {

    private   UserService userService = new UserServiceImpl();



    /**
     * 处理email异步校验
     */
    private void checkEmail(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //1、接收请求数据
        String email = request.getParameter("email");

        //2、处理数据:拿email到数据库中查询数据
        //返回值:true:校验通过(从数据库中没有查到数据)     false
        boolean checkFlag = userService.checkEmail(email);

        //3、响应数据
        response.getWriter().println(checkFlag);

    }





    /**
     * 处理注册数据提交
     */
    private void regist(HttpServletRequest request, HttpServletResponse response) throws IOException {

        //1、接收请求数据
        //获取整个表单数据
        Map<String, String[]> map = request.getParameterMap();

        //使用BeanUtils工具类,把map中的数据 封装到实体类中
        User user = new User();
        //封装结果集的map
        Map<String, Object> result = new HashMap<>();

        try {
            BeanUtils.populate(user,map);
            //2、处理数据:把user中的数据插入到数据库中,调用service层处理
            //registFlag:   true--成功  false--失败
            boolean registFlag = userService.regist(user);
            //注册成功-给用户发送激活邮件
            if (registFlag) {
                //给用户发送激活邮件
                MailUtil.sendEmail(user.getEmail(),
                        "<h1>恭喜您,注册成功!</h1><a href='http://localhost:8080/userServlet?methodName=active&code="+user.getCode()+"'>请点击此链接,进行激活</a>");
            }
            result.put("checkFlag", registFlag);

        } catch (Exception e) {
            e.printStackTrace();
            result.put("checkFlag", false);
            result.put("msg", "注册出现异常,请联系管理员!");
        }

        //3、响应数据:json   {name:value} -- map<key,value>
        String s = JSON.toJSONString(result);
        response.getWriter().println(s);
    }


    /**
     * 处理用户激活
     * @param request
     * @param response
     * @throws IOException
     */
    private void active(HttpServletRequest request,HttpServletResponse response) throws IOException {

        //1、接收请求数据
        String code = request.getParameter("code");

        //2、处理数据:根据激活码更新激活状态为1
        //activeFlag:  true-激活成功  false-失败
        boolean activeFlag =  userService.active(code);

        //3、响应数据
        if (activeFlag) {
            //成功----跳转到登录页面
            //定时刷新:
            response.getWriter().println("激活成功,3秒钟之后跳转到登录页面!");
            response.setHeader("refresh","3;/login.html");
            //response.sendRedirect("/login.html");
        }else{
            //失败 --- 跳转到注册页面
            response.getWriter().println("激活失败,请联系管理员,3秒钟之后跳转到注册页面!");
            response.setHeader("refresh","3;/register.html");
        }
    }


    /**
     * 处理用户登录业务
     * @param request
     * @param response
     * @throws IOException
     */
    private void login(HttpServletRequest request,HttpServletResponse response)throws IOException {

        //1、接收请求数据:整个表单
        Map<String, String[]> map = request.getParameterMap();

        //创建一个封装结果的map
        Map<String, Object> result = new HashMap<>();
        //把map中的数据封装到user中
        User user = new User();
        try {
            BeanUtils.populate(user,map);
            //2、处理数据:
            //2.1 验证码校验:
            //用户输入的验证码
            String userCode = request.getParameter("checkCode");
            //获取服务器端生成的验证码
            String serverCode  = (String) request.getSession().getAttribute("code");
            if (!serverCode.equalsIgnoreCase(userCode)) {
                //验证码校验不通过:1、给用户提示信息;2、登录失败;
                result.put("loginFlag",false);
                result.put("errorMsg", "验证码错误!");
                //响应数据
                response.getWriter().println(JSON.toJSONString(result));
                //终止程序
                return;
            }

            //2.2 用户登录:校验过程 email,password == 数据库
            User loginUser = userService.login(user);
            if (null == loginUser) {
                //登录失败:
                result.put("loginFlag",false);
                result.put("errorMsg", "用户名或密码错误!");
            }else{
                //登录成功:把登录用户的数据保存在session中
                request.getSession().setAttribute("loginUser",loginUser);
                result.put("loginFlag",true);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //登录失败:
            result.put("loginFlag",false);
            result.put("errorMsg", "服务器发生异常,请联系管理员!");
        }
        //3、响应数据
        response.getWriter().println(JSON.toJSONString(result));
    }




}

【Service层】UserService.java

package com.heima.travel.service;

import com.heima.travel.model.User; /**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:17
 * @description TODO
 **/
public interface UserService {
    boolean checkEmail(String email);

    boolean regist(User user) throws Exception;

    boolean active(String code);

    User login(User user) throws Exception;
}

【service层】UserServiceImpl.java

package com.heima.travel.service.impl;

import com.heima.travel.dao.UserDao;
import com.heima.travel.dao.impl.UserDaoImpl;
import com.heima.travel.model.User;
import com.heima.travel.service.UserService;
import com.heima.travel.utils.Md5Util;
import com.heima.travel.utils.UuidUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:17
 * @description 处理用户模块业务的Service实现类
 **/
public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDaoImpl();

    /**
     * 校验email的唯一性
     * @param email
     * @return
     */
    @Override
    public boolean checkEmail(String email) {

        //调用dao层  到数据库中查询数据
        List<User> userList =  userDao.queryByEmail(email);

        //userList != null  返回false
        if (null != userList && userList.size() > 0) {
            return  false;
        }

        return true;
    }


    /**
     * 提交注册数据
     * @param user
     * @return
     */
    @Override
    public boolean regist(User user) throws Exception {

        //处理注册数据:

        //1、设置激活状态为:0-未激活
        user.setStatus(0);
        //2、设置激活码
        user.setCode(UuidUtil.getUuid());

        //3、对密码加密处理
        //原始密码
        String password = user.getPassword();
        //加密
        String md5Pwd = Md5Util.encodeByMd5(password);
        user.setPassword(md5Pwd);

        //调用dao层插入数据
        int addNum = userDao.addUser(user);


        return addNum != 0;
    }


    /**
     * 处理用户激活
     * @param code
     * @return
     */
    @Override
    public boolean active(String code) {

        //调用dao层更新数据
        int updateNum = userDao.updateStatusByCode(code);

        return updateNum != 0;
    }


    /**
     * 处理登录业务
     * @param user
     * @return
     */
    @Override
    public User login(User user) throws Exception {
        //email  password:123456
        //把密码转换成密文
        String password = user.getPassword();
        String md5Pwd = Md5Util.encodeByMd5(password);
        user.setPassword(md5Pwd);


        //查询数据:email  md5Pwd
       return  userDao.queryByEmailAndPassword(user);
    }
}

【Dao层】UserDao.java

package com.heima.travel.dao;

import com.heima.travel.model.User;

import java.util.List;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:21
 * @description TODO
 **/
public interface UserDao {
    List<User> queryByEmail(String email);

    int addUser(User user);

    int updateStatusByCode(String code);

    User queryByEmailAndPassword(User user);
}

【Dao层】UserDaoImpl.java

package com.heima.travel.dao.impl;

import com.heima.travel.dao.UserDao;
import com.heima.travel.model.User;
import com.heima.travel.utils.C3p0Utils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/17 17:21
 * @description 处理用户模块CRUD的dao实现类
 **/
public class UserDaoImpl implements UserDao {

    //初始化模板
    private JdbcTemplate jdbcTemplate = new JdbcTemplate(C3p0Utils.getDataSource());


    @Override
    public List<User> queryByEmail(String email) {
        String sql = "SELECT * FROM tab_user WHERE email=?";
       return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class), email);
    }


    /**
     * 数据录入
     * @param user
     * @return
     */
    @Override
    public int addUser(User user) {
        String sql = "INSERT INTO tab_user VALUES(NULL,?,?,?,?,?,?,?,?,?)";
        return jdbcTemplate.update(sql,
                user.getUsername(),
                user.getPassword(),
                user.getName(),
                user.getBirthday(),
                user.getSex(),
                user.getTelephone(),
                user.getEmail(),
                user.getStatus(),
                user.getCode());
    }


    /**
     * 根据code更新status为1
     * @param code
     * @return
     */
    @Override
    public int updateStatusByCode(String code) {
        String sql = "UPDATE tab_user SET status = 1 WHERE code = ? AND status = 0";
        return jdbcTemplate.update(sql,code);
    }


    /**
     *
     * 根据email和password查询数据
     * @param user
     * @return
     */
    @Override
    public User queryByEmailAndPassword(User user) {

        String sql = "SELECT * FROM tab_user WHERE email = ? AND password = ? AND status=1";

        try {
           return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), user.getEmail(), user.getPassword());
        } catch (DataAccessException e) {
            e.printStackTrace();
            return null;
        }


    }


}

3.6 用户注册–邮件激活

注:邮箱相关设置请参考,资料中邮件相关资料—《Commons Mail入门》。

​ 用户注册成功之后,系统需要发用邮件至用户填写的email。要求如下:

  1. 用户注册成功后,发送邮件到用户的email;
  2. 发送的email的信息如下:

在这里插入图片描述

  1. 用户点击激活链接后进行激活业务处理:
    1. 激活成功:给出提示信息,跳转到登录页面;
    2. 激活失败:给出提示信息,提示用户重新注册;
3.6.1 邮件发送
第一步:引入Apache mail依赖
<!--apache mail-->
<dependency>
  	<groupId>org.apache.commons</groupId>
  	<artifactId>commons-email</artifactId>
  	<version>1.5</version>
</dependency>
第二步:测试邮件发送

【commons mail开发步骤】

第一步:创建HtmlEmail对象;
第二步:设置邮箱服务器相关参数:
	1、服务器地址;
	2、授权码;
	3、编码集;
第三步:设置收件人与发件人参数;
第四步:设置邮件正文内容;
第五步:发送邮件;

【测试代码】


    /*
    * 发送邮件:
    *       网易 ==》139邮箱
    * */
    @Test
    public  void testSendEmail() throws EmailException {

        //1、创建一个HtmlEmail对象
        HtmlEmail htmlEmail = new HtmlEmail();
        //2、设置邮箱服务器的参数
        htmlEmail.setHostName("smtp.qq.com");
        //设置编码-
        htmlEmail.setCharset("gbk");


        //3、设置邮箱验证(客户端授权)
        //username:邮箱账号
        //password:客户端授权码
        htmlEmail.setAuthentication("1084169217@qq.com","lwrigaycytgbgiha");

        //4、设置收件人 和 发件人
        htmlEmail.setFrom("1084169217@qq.com", "aaa");
        htmlEmail.addTo("13774213770@139.com", "139");

        //5、设置主题 和  正文
        htmlEmail.setSubject("【黑马65测试二.....】");
        htmlEmail.setTextMsg("张弛发来贺电..............");

        //6、发送邮件
        htmlEmail.send();

    }

第三步:抽取MailUtil工具类
  1. 将邮箱的配置信息,填写到mail.properties文件中
host.name=smtp.163.com
authen.name=buguniaoyst@163.com
authen.pwd=buguniao199
charset=GB2312
  1. 将邮件发送固定信息封装到HtmlEmail实体类中
package com.heima.travel.utils;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;

import java.util.ResourceBundle;

/**
 * @author buguniao
 * @version v1.0
 * @date 2019/3/19 16:17
 * @description 邮件发送的工具类
 **/
public class MailUtil {

    private static String host;
    private static String charset;
    private static String username;
    private static String password;


    /**
     * 静态代码块加载配置信息
     */
    static {

        ResourceBundle bundle = ResourceBundle.getBundle("mail");
        host = bundle.getString("mail.host");
        charset = bundle.getString("mail.charset");
        username = bundle.getString("mail.username");
        password = bundle.getString("mail.password");
    }


    /**
     * 发送邮件
     * @param emailTo
     * @param msg
     */
    public static void sendEmail(String emailTo,String msg) throws EmailException {

        //1、创建一个HtmlEmail对象
        HtmlEmail htmlEmail = new HtmlEmail();
        //2、设置邮箱服务器的参数
        htmlEmail.setHostName(host);
        //设置编码-
        htmlEmail.setCharset(charset);

        //3、设置邮箱验证(客户端授权)
        //username:邮箱账号
        //password:客户端授权码
        htmlEmail.setAuthentication(username,password);

        //4、设置收件人 和 发件人
        htmlEmail.setFrom(username, "【黑马旅游官方】");

        htmlEmail.addTo(emailTo, "【注册用户】");

        //5、设置主题 和  正文
        htmlEmail.setSubject("【黑马旅游注册激活邮件】");
        //网易
        //htmlEmail.setTextMsg(msg);

        //qq
        htmlEmail.setHtmlMsg(msg);

        //6、发送邮件
        htmlEmail.send();
    }


}

第四步:将邮件发送业务添加到UserServlet.java中

​ 注册成功发送邮件。
在这里插入图片描述

if (registFlag) {
                //给用户发送激活邮件
                MailUtil.sendEmail(user.getEmail(),
                        "<h1>恭喜您,注册成功!</h1><a href='http://localhost:8080/userServlet?methodName=active&code="+user.getCode()+"'>请点击此链接,进行激活</a>");
            }
3.6.2 邮件激活业务

​ 邮件激活业务流程:

  1. 根据邮件链接中的激活码更新用户的激活状态为:1—已激活;
  2. 激活成功—跳转到login.html,激活失败—跳转到register.html页面;

【web层】UserServlet.java

/**
     * 邮箱激活
     * @param request
     * @param response
     * @throws Exception
     */
    public void active(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //处理邮件激活业务
        //1.获取请求数据
        //激活码
        String code = request.getParameter("code");
        //2.处理数据
        boolean activeFlag = userService.emailActive(code);
        //3.响应数据
        if (activeFlag) {
            //激活成功  重定向到登录页面
            response.getWriter().println("邮件激活成功,即将跳转到登录页面");
            response.setHeader("refresh","3;/login.html");
        }else{
            //激活失败,响应失败信息
            response.getWriter().println("邮件激活失败,3秒中之后将跳转到注册页面,请重新注册");
            response.setHeader("refresh","3;/register.html");
        }
    }

【Service层】UserService.java

/**
 * 邮件激活
 * @param code
 * @return
*/
public boolean emailActive(String code) {
      //根据code跟新激活状态
      int updateFlag = userDao.updateActiveStatusByCode(code);
      return updateFlag != 0;
}

【Dao层】UserDao.java

int updateActiveStatusByCode(String code);

【Dao实现类】UserDaoImpl.java

@Override
public int updateActiveStatusByCode(String code) {
    String sql = "UPDATE tab_user SET status = 1 WHERE code= ? AND status=0";
    return jdbcTemplate.update(sql,code);
}

第四章 作业

1、搭建项目环境;

2、注册:数据校验(前端+后台);

  • 完成黑马旅游项目环境搭建
  • 完成注册数据前端校验
  • 完成注册email后台唯一性校验
  • 完成注册数据添加到数据库业务
  • 完成注册成功,邮件发送业务
  • 完成邮件激活业务
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值