typora-copy-images-to: img
day01-黑马旅游
学习目标
-[ ] 了解项目的生命周期
-[ ] 能够完成用户注册案例
-[ ] 能够完成BaseServlet优化请求处理
第一章 项目生命周期【了解】
1.1 项目生命周期
完整地开发一个java项目一般都会经历以下几个阶段:
- 项目立项:确定项目研发;
- 需求阶段:《需求说明书》—不涉及技术,只涉及业务;
- 概要设计阶段:《概要设计说明书》—涉及技术选型和数据库设计阶段;
- 详细设计阶段:《详细设计说明书》—涉及业务的细节点(伪代码);
- 编码阶段:coding阶段–单元测试–模块测试—联测(程序员在开发环境自己测试);
- 测试组测试:《测试报告》;
- 公测阶段:参与人员–程序员,测试人员,真实用户;
- 发布上线;
- 维护和二次开发…;
1.2 黑马旅游技术选型与环境
1.2.1 黑马旅游项目简介
黑马旅游网是一个类似途牛网和携程网的旅游预订平台。在这个平台中,我们需要完成基本的用户模块相关的功能和旅游线路 产品相关的功能以及对旅游产品的收藏 等功能。
1.2.2 技术选型
技术选型就是确定完成项目开发要使用到的技术。《黑马旅游》中使用到的技术如下:
技术 | 版本 | 说明 |
---|---|---|
Servlet | 3.1.0 | 处理客户端请求和响应,注解开发 |
BeanUtils | 1.8.3 | 封装客户端请求的数据 |
Spring JdbcTemplate | 4.1.2 | JDBC工具类 |
C3P0 | 0.9 | 数据库连接池技术 |
Jedis | 2.8 | java版的redis客户端实现 |
1.2.3 开发工具与环境
在企业往往是一个团队开发一个项目,为了避免团队中因工具版本带来的问题。正式开发之前往往需要先统一开发环境,以下是《黑马旅游》项目开发过程中需要统一的环境说明。
工具 | 版本 | 说明 |
---|---|---|
IDEA | 2017.3 | 开发工具 |
JDK | 1.8 | java开发环境 |
Maven | 3.2.3 | 项目管理工具 |
Redis | 2.8.9 | 非关系型数据库 |
MySQL | 5.6 | 数据库 |
1.2.4 开发模式
黑马旅游采用前后端分离的模式进行开发。前端开发人员负责页面的编写及数据的渲染。后端开发人员负责提供API(接口)。前后端采用指定的API接口进行交互。
第二章 搭建项目环境
2.1 创建maven的web工程
使用idea创建maven的web工程。并正确设置web项目的目录结构。
- 将项目的打包方式改为war;
- 设置正确的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 用户注册需求
需求- 需求分析 -》代码
用户注册,就是将用户在页面上输入的数插入到数据库中。但是,插入之前需要对用户提交的数据进行校验。校验分为前端校验和后端校验。完成用户注册业务要求如下:
- 注册数据处理:
- 前端校验:数据完整性与合法性校验
- 后台校验:数据唯一性校验
- 数据处理:将数据插入到数据库
- 邮件激活:
- 邮件发送:注册成功发送激活邮件
- 激活:根据激活码激活
- 响应处理:
- 注册数据添加成功:跳转到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插件,对页面数据进行校验。实现步骤如下:
- 导入jquery.validate.js文件。注意:放在jquery后面:
- 使用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
- 发送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请求优化一
- 用户业务相关的请求集中请求同一个servlet—UserServlet;
- 每个请求都携带一个
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。要求如下:
- 用户注册成功后,发送邮件到用户的email;
- 发送的email的信息如下:
- 用户点击激活链接后进行激活业务处理:
- 激活成功:给出提示信息,跳转到登录页面;
- 激活失败:给出提示信息,提示用户重新注册;
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工具类
- 将邮箱的配置信息,填写到mail.properties文件中
host.name=smtp.163.com
authen.name=buguniaoyst@163.com
authen.pwd=buguniao199
charset=GB2312
- 将邮件发送固定信息封装到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—已激活;
- 激活成功—跳转到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后台唯一性校验
- 完成注册数据添加到数据库业务
- 完成注册成功,邮件发送业务
- 完成邮件激活业务