概述

(一)功能分析
(二)前台:表单校验
(三)前台:异步提交表单
(四)后台:Servlet代码的实现
(五)后台:Dao代码的实现
(六)后台:service代码的实现&测试
(七)后台:验证码&前台数据处理
(八)后台:邮件激活分析
(九)后台:发送邮件分析
(十)后台:点击激活分析
(十一)后台:邮件激活代码实现之Servlet
(十二)后台:邮件激活代码实现之service&Dao

(一)功能分析

(二)前台:表单校验

	 <script>
        /*
            表单校验:
                1.用户名:单词字符,长度8到20位
                2.密码:单词字符,长度8到20位
                3.email:邮件格式
                4.姓别:非空(因为是单选框)
                5.手机号:手机号格式
                6.出生日期:非空(因为使用了H5的插件)
                7.验证码:非空
         */

        //校验用户名
        function checkUsername() {
            //1.获取用户名的值
            var username = $("#username").val();
            //2.定义正则
            var reg_username = /^\w{8,20}$/;
            //3.判断,给出提示信息
            var flag = reg_username.test(username);
            if (flag) {
                //用户名合法
                $("#username").css("border", "");
            } else {
                //用户名非法,加一个红色的边框
                $("#username").css("border", "1px solid red");
            }
            return flag;
        }

        //校验密码
        function checkPassword() {
            //1.获取密码的值
            var password = $("#password").val();
            //2.定义正则
            var reg_password = /^\w{8,20}$/;
            //3.判断,给出提示信息
            var flag = reg_password.test(password);
            if (flag) {
                //密码合法
                $("#password").css("border", "");
            } else {
                //密码非法,加一个红色的边框
                $("#password").css("border", "1px solid red");
            }
            return flag;
        }

        //校验邮箱
        function checkEmail() {
            //1.获取邮箱
            var email = $("#email").val();
            //2.定义正则   itcast@163.com
            var reg_email = /^\w+@\w+\.\w+$/;
            //3.判断
            var flag = reg_email.test(email);
            if (flag) {
                $("#email").css("border", "");
            } else {
                $("#email").css("border", "1px solid red");
            }
            return flag;
        }


        $(function () {
            //当表单提交时,调用所有的校验方法
            $("#registerForm").submit(function () {
                return checkUsername() && checkPassword() && checkEmail();//只有都为真,表单才会提交
                //如果这个方法(这个匿名的function方法)没有返回值,或者返回为true,则表单提交;反之不提交
            });

            //当某一个组件失去焦点时,调用对应的校验方法
            $("#username").blur(checkUsername);
            $("#password").blur(checkPassword);
            $("#email").blur(checkEmail);

        });
        
    </script>

(三)前台:异步提交表单

在此使用异步提交表单是为了获取服务器响应的数据
因为我们前台使用的是html作为视图层,不能够像JSP一样直接从servlet相关的域对象获取值
只能通过ajax获取响应数据

        $(function () {
            //当表单提交时,调用所有的校验方法
            $("#registerForm").submit(function () {
                //1.发送数据到服务器
                if (checkUsername() && checkPassword() && checkEmail()) {
                    //校验通过,发送ajax请求,提交表单的数据
                    $.post("registUserServlet", $(this).serialize(), function (data) {
                        
                    });
                }
                //2.跳转页面

                // return checkUsername() && checkPassword() && checkEmail();//只有都为真,表单才会提交
                return false;
                //如果这个方法(这个匿名的function方法)没有返回值,或者返回为true,则表单提交;反之不提交
            });

            //当某一个组件失去焦点时,调用对应的校验方法
            $("#username").blur(checkUsername);
            $("#password").blur(checkPassword);
            $("#email").blur(checkEmail);

        });

(四)后台:Servlet代码的实现

  • 前提(一):写一个作用于所有请求的过滤器,用于处理字符集编码的问题

    代码:
/**
 * 解决全站乱码问题,处理所有的请求
 */
@WebFilter("/*")
public class CharchaterFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse rep, FilterChain filterChain) throws IOException, ServletException {
        //将父接口转为子接口
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) rep;
        //获取请求方法
        String method = request.getMethod();
        //解决post请求中文数据乱码问题
        if (method.equalsIgnoreCase("post")) {
            request.setCharacterEncoding("utf-8");
        }
        //处理响应乱码
        response.setContentType("text/html;charset=utf-8");
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}
  • 前提(二):写一个类,用于封装后端返回前端数据对象

    代码:
/**
 * 用于封装后端返回前端数据对象
 */
public class ResultInfo implements Serializable {
    private boolean flag;//后端返回结果正常为true,发生异常返回false
    private Object data;//后端返回结果数据对象
    private String errorMsg;//发生异常的错误消息

    //无参构造方法
    public ResultInfo() {
    }
    public ResultInfo(boolean flag) {
        this.flag = flag;
    }
    /**
     * 有参构造方法
     * @param flag
     * @param errorMsg
     */
    public ResultInfo(boolean flag, String errorMsg) {
        this.flag = flag;
        this.errorMsg = errorMsg;
    }
    /**
     * 有参构造方法
     * @param flag
     * @param data
     * @param errorMsg
     */
    public ResultInfo(boolean flag, Object data, String errorMsg) {
        this.flag = flag;
        this.data = data;
        this.errorMsg = errorMsg;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }
}
  • RegistUserServlet.java
@WebServlet("/registUserServlet")
public class RegistUserServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取数据
        Map<String, String[]> map = request.getParameterMap();
        //2.封装对象
        User user = new User();
        try {
            BeanUtils.populate(user, map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        //3.调用service完成注册
        UserService service = new UserServiceImpl();
        boolean flag = service.regist(user);
        //4.响应结果
        ResultInfo info = new ResultInfo();
        if (flag) {
            //注册成功
            info.setFlag(true);
        } else {
            //注册失败
            info.setFlag(false);
            info.setErrorMsg("注册失败!");
        }

        //讲info对象序列化为json
        ObjectMapper mapper = new ObjectMapper();
        String json = mapper.writeValueAsString(info);
        //讲json数据写回客户端
        //设置content-type
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(json);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}

(五)后台:Dao代码的实现

我们根据UserServiceImpl的两个需求分别写两个Dao类的方法

写Dao类的方法之前,先在Dao类的接口

public interface UserDao {
    /**
     * 根据用户名查询用户信息
     *
     * @param username
     * @return
     */
    public User findByUsername(String username);

    /**
     * 用户保存
     *
     * @param user
     */
    public void save(User user);
}

接下来写Dao的实现类

public class UserDaoImpl implements UserDao {
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    @Override
    public User findByUsername(String username) {
        //1.定义sql
        String sql = "select * from tab_user where username = ?";
        //2.执行sql
        User user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
        return user;
    }

    @Override
    public void save(User user) {
        //1.定义sql
        String sql = "insert into user(username,password,name,birthday,sex,telephone,email) values(?,?,?,?,?,?,?)";
        //2.执行sql
        template.update(sql, user.getUsername(),
                user.getPassword(),
                user.getName(),
                user.getBirthday(),
                user.getSex(),
                user.getTelephone(),
                user.getEmail());
    }
}

(六)后台:service代码的实现&测试

在写service代码之前先注意一个问题
使用JdbcTemplate的queryForObject()方法,如果查询不到用户,不会返回Null,而实直接抛出异常

所以我们要捉异常

    @Override
    public User findByUsername(String username) {
        User user = null;
        try {
            //1.定义sql
            String sql = "select * from tab_user where username = ?";
            //2.执行sql
            user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), username);
        } catch (Exception e) {

        }
        
        return user;
    }

UserServiceImpl.java

public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDaoImpl();

    /**
     * 注册用户
     *
     * @param user
     * @return
     */
    @Override
    public boolean regist(User user) {
        //1.根据用户名查询用户对象
        User u = userDao.findByUsername(user.getUsername());
        //判断u是否为null
        if (u != null) {
            //用户名存在,注册失败
            return false;
        }
        //2.保存用户信息
        userDao.save(user);
        return true;
    }
}

注意:黑马的教程用的mysql版本是5,我们的是8,要进行以下变动

  1. pom.xml的mysql驱动版本号
  2. 把我们旧项目的JDBCUtils导进来(详情见JDBC文集)
  3. druid.properties文件加上cj(详情见JDBC文集)
  4. druid.properties的url后面加上?useSSL=true&serverTimezone=UTC

(七)后台:验证码&前台数据处理

我们把验证码校验的代码写在最前面,如果验证码错误,就不必进行其他的校验了

        //验证码校验
        String check = request.getParameter("check");
        //从session中获取验证码
        HttpSession session = request.getSession();
        String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
        session.removeAttribute("CHECKCODE_SERVER");//为了保证验证码只能使用一次
        //比较
        if (checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)) {
            //验证码错误
            ResultInfo info = new ResultInfo();
            info.setFlag(false);
            info.setErrorMsg("验证码错误!");
            //讲info对象序列化为json
            ObjectMapper mapper = new ObjectMapper();
            String json = mapper.writeValueAsString(info);
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(json);
            return;
        }

前台页面跳转代码如下:

	  $.post("registUserServlet", $(this).serialize(), function (data) {
	      if (data.flag) {
	          //注册成功,跳转成功页面
	          location.href = "register_ok.html";
	      } else {
	          //注册失败,给errorMsg添加提示信息
	          $("#errorMsg").html(data.errorMsg);
	
	      }
	  });

注意:此时有一个前端的BUG,注册失败需要手动刷新验证码
我们需要在展示错误信息的代码下面加一行代码

(八)后台:邮件激活分析

为什么要进行邮件激活?

  1. 为了保证用户填写的邮箱是正确的
  2. 将来可以推广一些宣传信息,到用户邮箱中

(九)后台:发送邮件分析

先准备一个MailUtils工具类

/**
 * 发邮件工具类
 */
public final class MailUtils {
    private static final String USER = ""; // 发件人称号,同邮箱地址
    private static final String PASSWORD = ""; // 如果是qq邮箱可以使户端授权码,或者登录密码

    /**
     * @param to    收件人邮箱
     * @param text  邮件正文
     * @param title 标题
     */
    /* 发送验证信息的邮件 */
    public static boolean sendMail(String to, String text, String title) {
        try {
            final Properties props = new Properties();
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.host", "smtp.qq.com");

            // 发件人的账号
            props.put("mail.user", USER);
            //发件人的密码
            props.put("mail.password", PASSWORD);

            // 构建授权信息,用于进行SMTP进行身份验证
            Authenticator authenticator = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    // 用户名、密码
                    String userName = props.getProperty("mail.user");
                    String password = props.getProperty("mail.password");
                    return new PasswordAuthentication(userName, password);
                }
            };
            // 使用环境属性和授权信息,创建邮件会话
            Session mailSession = Session.getInstance(props, authenticator);
            // 创建邮件消息
            MimeMessage message = new MimeMessage(mailSession);
            // 设置发件人
            String username = props.getProperty("mail.user");
            InternetAddress form = new InternetAddress(username);
            message.setFrom(form);

            // 设置收件人
            InternetAddress toAddress = new InternetAddress(to);
            message.setRecipient(Message.RecipientType.TO, toAddress);

            // 设置邮件标题
            message.setSubject(title);

            // 设置邮件的内容体
            message.setContent(text, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) throws Exception { // 做测试用
        MailUtils.sendMail("itcast_xian@163.com", "你好,这是一封测试邮件,无需回复。", "测试邮件");
        System.out.println("发送成功");
    }
    
}

配置了网易邮箱发现无法通过测试,配置过程如下:



用同样的方法配置了qq邮箱,并且获得授权码,填到工具类中可以通过测试,如下:

我们从QQ邮箱发送到网易邮箱

效果如下:

(十)后台:点击激活分析

需求分析:

我们看看User类:

所以用户点击超链接激活,后端只需要把该用户的status字段从N改成Y即可
详细分析:

我们先编写UserServiceImpl

public class UserServiceImpl implements UserService {

    private UserDao userDao = new UserDaoImpl();

    /**
     * 注册用户
     *
     * @param user
     * @return
     */
    @Override
    public boolean regist(User user) {
        //1.根据用户名查询用户对象
        User u = userDao.findByUsername(user.getUsername());
        //判断u是否为null
        if (u != null) {
            //用户名存在,注册失败
            return false;
        }

        //2.保存用户信息
        //2.1设置激活码,唯一字符串
        user.setCode(UuidUtil.getUuid());
        //2.2设置激活状态
        user.setStatus("N");
        userDao.save(user);
        //3.激活邮件发送
        String content = "<a href='http://localhost/travel/activeUserServlet?code=" + user.getCode() + "'>点击激活【黑马旅游网】</a>";
        MailUtils.sendMail(user.getEmail(), content, "激活邮件");
        return true;
    }
}

效果如下:


注意:我们这里封装Java的UuidUtil工具类来生成全球唯一的字符串

/**
 * 产生UUID随机字符串工具类
 */
public final class UuidUtil {
	private UuidUtil(){}
	public static String getUuid(){
		return UUID.randomUUID().toString().replace("-","");
	}
	/**
	 * 测试
	 */
	public static void main(String[] args) {
		System.out.println(UuidUtil.getUuid());
		System.out.println(UuidUtil.getUuid());
		System.out.println(UuidUtil.getUuid());
		System.out.println(UuidUtil.getUuid());
	}
}

(十一)后台:邮件激活代码实现之Servlet

@WebServlet("/activeUserServlet")
public class ActiveUserServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取激活码
        String code = request.getParameter("code");
        if (code != null) {
            //2.调用service完成激活
            UserService service = new UserServiceImpl();
            boolean flag = service.active(code);
            //3.判断
            String msg = null;
            if (flag) {
                //激活成功
                msg = "激活成功,请<a href='login.html'>登录</a>";
            } else {
                //激活失败
                msg = "激活失败,请联系管理员!";
            }
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(msg);
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }
}


(十二)后台:邮件激活代码实现之service&Dao

我们先把save方法完善,如下:

UserServiceImpl

    /**
     * 激活用户
     *
     * @param code
     * @return
     */
    @Override
    public boolean active(String code) {
        //1.根据激活码查询用户对象
        User user = userDao.findByCode(code);
        //2.调用dao的修改激活状态的方法
        if (user != null) {
            userDao.updateStatus(user);
            return true;
        } else {
            return false;
        }
    }

UserDao

    /**
     * 根据激活码查询用户对象
     *
     * @param code
     * @return
     */
    User findByCode(String code);

    /**
     * 修改执行用户的激活状态
     *
     * @param user
     */
    void updateStatus(User user);

UserDaoImpl

    /**
     * 根据激活码查询用户对象
     *
     * @param code
     * @return
     */
    @Override
    public User findByCode(String code) {
        User user = null;
        try {
            String sql = "select * from tab_user where code = ?";
            user = template.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), code);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return user;
    }

    /**
     * 修改执行用户的激活状态
     *
     * @param user
     */
    @Override
    public void updateStatus(User user) {
        String sql = "update user set status = 'Y' where id = ?";
        template.update(sql, user.getUid());
    }

效果:

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐