作者:L_J
????????现如今有很多的注册登陆页面你是否也面临过一些你注册完成之后登录前还需要进行账号激活的情况呢?你是否也想知道它的实现原理呢?下面就是我学到的账号激活的一种方式的自我理解进行一下分享欢迎一起来探讨学习。
一、注册页面
既然涉及到了注册那么必不可少的就是页面了,下面的代码是我easyui写的一个简单的注册页面这些页面easyui官网是给你提供了的你只需要去用它就行,你尽然用了别人写好的页面哪当然也是需要对它的一些css及js的导入它需要什么你就导入什么。你下载的easyui它会给你提供它所要用到得一些css及js。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Basic Form - jQuery EasyUI Demo</title>
<link rel="stylesheet" type="text/css" href="themes/default/easyui.css">
<link rel="stylesheet" type="text/css" href="themes/icon.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.easyui.min.js"></script>
</head>
<body>
<h2>Basic Form</h2>
<p>Fill the form and submit it.</p>
<div style="margin:20px 0;"></div>
<div class="easyui-panel" title="New Topic" style="width:100%;max-width:400px;padding:30px 60px;">
<form id="ff" action="user?action=register" method="post">
<div style="margin-bottom:20px">
<input class="easyui-textbox" name="name" style="width:100%" data-options="label:'Name:',required:true">
</div>
<div style="margin-bottom:20px">
<input class="easyui-textbox" name="pass" style="width:100%" data-options="label:'pass:',required:true">
</div>
<div style="margin-bottom:20px">
<input class="easyui-textbox" name="email" style="width:100%" data-options="label:'Email:',required:true,validType:'email'">
</div>
<div style="text-align:center;padding:5px 0">
<input type="submit" value="提交">
</div>
</form>
</div>
</body>
</html>
二、mvc开发模式进行与数据库的交互
上面的代码中可以看到我的提交路径:user?action=register这是什么意思能?uer它是一个servlet的一个虚拟路径?后面的是路径中携带的参数。我这里参数是一个方法的方法名。servlet代码如下:
@WebServlet("/user")
public class UserServlet extends BaseServlet{
CustomerService service=new CustomerServiceImp();
public void register(HttpServletRequest req,HttpServletResponse resp){
//将表单中的数据映射到对象中去
Customer customer = ConverterBeanUtils.toBean(req.getParameterMap(),Customer.class);
customer.setActivate(0);
//将拿到的随机字符串设置为激活码
customer.setCode(UUIDUtils.getUUID());
boolean b=service.register(customer);
}
}
entity代码如下:
遵循javabean的封装原则 这里的属性名要和数据库的字段名相同
public class Customer {
private int id;
private String name;
private String pass;
//0代表未激活 1代表激活
private int activate;
//保存验证码
private String code;
private String email;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public int getActivate() {
return activate;
}
public void setActivate(int activate) {
this.activate = activate;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Customer() {
super();
// TODO Auto-generated constructor stub
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + ", pass=" + pass + ", activate=" + activate + ", code=" + code
+ ", email=" + email + "]";
}
这里我的servlet并不是用的xml来进行配置的而是直接用的注解来配置我的servlet。
你可能很疑惑为什么我的servlet继承不是HttpServlet而是BaseServlet因为我将HttpServlet用反射机制进行了封装利用反射机制去帮我们拿到类中的方法,从而避免了我们在servlet中每增加一个方法我们就需要写一个判断的问题而是可以直接在访问servlet的时候传递一个方法名过来这里我不做过多的讲解我在下面会附上BaseServlet封装类中的代码。在servlet中我们给了一个随机的激活码他是怎么来的能?我们用到了一个叫UUID的东西,当然你在代码中所看到的也是我封装后的样子它的封装代码也会放在下面。
service代码如下:
public interface CustomerService {
boolean register(Customer customer);
Customer active(String code);
boolean updateCustomer(Customer c);
}
BaseServlet代码如下:
在代码里面我写了很多的注释去讲解 可自行去看一下
@WebServlet("/base")
public class BaseServlet extends HttpServlet {
@Override
//访问servlet虚拟路径的时候会访问到这个方法
public void service(HttpServletRequest request, HttpServletResponse response){
//设计字符集编码
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset:UTF-8");
//拿到虚拟的路径
String MethodName=request.getParameter("action");
//赋初值方便下面调用
Method method=null;
//判断拿到的虚拟路径是否为空
if(MethodName==null){
throw new RuntimeException(MethodName+"=null请填写合法的action");
}
try {
//拿到当前类对象那个并拿到类中的方法
method= this.getClass().getMethod(MethodName,HttpServletRequest.class,HttpServletResponse.class);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException("找不到"+MethodName+"()方法");
}
try {
//调用类中的方法
String invoke = (String)method.invoke(this,request,response);
if(invoke!=null && !invoke.trim().isEmpty()){
//查找字符串中是否包含指定字符
int indexOf = invoke.indexOf(":");
//-1代表不包含
if(indexOf==-1){
try {
//如果不包含指定字符默认指定为转发
request.getRequestDispatcher(invoke).forward(request,response);
} catch (ServletException | IOException e) {
e.printStackTrace();
}
//包含指定字符
}else{
//使用指定字符进行分割
String[] split = invoke.split(":");
//拿到分割后的前缀 (判断转发还是重定向)
String prefix = split[0];
//拿到分割后的后缀 (路径)
String path = split[1];
//前缀等于f
if("f".equals(prefix)){
try {
//就指定为转发
request.getRequestDispatcher(path).forward(request, response);
} catch (ServletException | IOException e) {
e.printStackTrace();
}
// 前缀为r
}else if("r".equals(prefix)){
try {
//指定为重定向
//request.getContextPath()获取到项目路径
response.sendRedirect(request.getContextPath()+"/"+path);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
throw new RuntimeException("该程序内部出现异常!");
}
}
}
UUIDUtils代码如下:
代码中写了很多注释在这就不过多的讲解了
public class UUIDUtils {
public static String getUUID(){
//拿到一个32位的随机字符串
//用UUID拿到的随机字符串会带有斜杠 将UUID转换为字符串并将字符串中的斜杠转换为""
return UUID.randomUUID().toString().replace("-","");
}
}
很明显这是一个接口,接口中的方法都是抽象方法。
serviceimp代码如下:
public class CustomerServiceImp implements CustomerService {
CustomerDao dao=new CustomerDaoImp();
public boolean register(Customer customer) {
boolean b=dao.register(customer);
if(b){
boolean sendEmail = EmailUtils.sendEmail(customer.getEmail(),"网站激活码",
"<h3>恭喜你成功注册为我站会员请点击下方链接进行激活</h3><br><a href='http://"+HostUtils.getHost()+":8080/SchickenSieEine-Email2/customer?action=active&code="+customer.getCode()+"'>立即激活</a>");
return sendEmail;
}
return false;
}
@Override
public Customer active(String code) {
return dao.active(code);
}
@Override
public boolean updateCustomer(Customer c) {
return dao.updateCustomer(c);
}
}
在实现类中我们可以看到在我们进行了一封邮件的发送,在你看了代码你可能会感慨 原来java实现发一封邮件这么简单啊。我告诉你并没有那么简单但也没有那么难,你现在看到的只是我将邮件的发送进行了封装。
EmailUtils代码如下:
public class EmailUtils {
//创建对象
static Properties properties=new Properties();
static{
try {
//拿到跟目录(src文件夹下)下的properties文件
InputStream in = EmailUtils.class.getClassLoader().getResourceAsStream("Email.properties");
//加载流中的数据
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public static boolean sendEmail(String to,String subject,String content){
try {
Properties props=new Properties();
//设置发送的邮箱方式 qq邮箱163邮箱等
props.setProperty("mail.host",properties.getProperty("host"));
//设置发送邮件是否需要校验
props.setProperty("mail.smtp.auth",properties.getProperty("auth"));
//设置发送邮件所使用的协议 这里用到的是smtp
props.setProperty("mail.transport.protocol",properties.getProperty("protocol"));
//创建对象
Authenticator authenticator=new Authenticator() {
//重写内部类中的方法
@Override
protected PasswordAuthentication getPasswordAuthentication() {
//拿到邮箱服务器的账号及密码 注意:这里的密码服务器的密码不是邮箱的密码
return new PasswordAuthentication(properties.getProperty("username"), properties.getProperty("passworld"));
}
};
//获取连接对象
Session session = Session.getInstance(props, authenticator);
//创建一封邮件
MimeMessage m=new MimeMessage(session);
//设置邮件的标题
m.setSubject(subject);
//设置邮件的发送人
m.setFrom(new InternetAddress(properties.getProperty("username")));
//设置发送方式及邮箱收件人
m.setRecipients(RecipientType.TO,to);
//设置邮件内容 内容格式及编码格式
m.setContent(content,"text/html;charset=utf-8");
//发送邮件
Transport.send(m);
//程序运行到这就表示邮件发送成功
return true;
} catch (Exception e) {
e.printStackTrace();
//程序遇到异常表示邮件发送失败
return false;
}
}
}
dao层代码如下:
dao层又叫数据库交互层 由名字可以看出它是进行与数据库交互的。下面代码可以看出它也是一个接口那么它就有实现类.
public interface CustomerDao {
boolean register(Customer customer);
Customer active(String code);
boolean updateCustomer(Customer c);
}
daoImp代码如下:
public class CustomerDaoImp implements CustomerDao {
QueryRunner runn=new QueryRunner(MyC3p0Utils.getDatSoutrce());
//注册 将注册信息添加到数据库表中
@Override
public boolean register(Customer customer) {
String sql="insert into customer values(null,?,?,?,?,?)";
try {
int update = runn.update(sql,customer.getName(),customer.getPass(),customer.getActivate(),customer.getCode(),customer.getEmail());
return update>0?true:false;
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
//查询是否有这个激活码
@Override
public Customer active(String code) {
String sql="select * from customer where code=?";
try {
return runn.query(sql,new BeanHandler<>(Customer.class),code);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
//查询到了激活码并激活了 修改数据库表中的activate 并将激活码置空避免用户重复激活
@Override
public boolean updateCustomer(Customer c) {
String sql="update customer set activate=?,code=? where id=?";
try {
int update = runn.update(sql,c.getActivate(),c.getCode(),c.getId());
return update>0?true:false;
} catch (SQLException e) {
throw new RuntimeException(e.getMessage());
}
}
}
三、用户激活servlet
当用户点击了邮件中的激活就到了这个方法中进行用户的激活。在用户点击激活的时候会传递过来一个code激活码通过这个激活码进行数据库查询,如果查到了就可以进行激活操作并将activate设置为1将code设置为null表示用户已激活这只是赋值到了对象中 与数据库进行交互将原数据库表进行修改。修改成功后向页面响应一个提示。也可以转发到指定的页面我就给了一个简单的提示。
@WebServlet("/customer")
public class CustomerServlet extends BaseServlet {
CustomerService service=new CustomerServiceImp();
public void active(HttpServletRequest req,HttpServletResponse resp){
String code = req.getParameter("code");
Customer c=service.active(code);
if(c!=null){
c.setActivate(1);
c.setCode(null);
boolean b=service.updateCustomer(c);
if(b){
try {
resp.getWriter().write("激活成功");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
try {
resp.getWriter().write("激活失败");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}else{
try {
resp.getWriter().write("请勿重复激活");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
四、总结
????????在本次小项目中用到的知识点easyui、mvc开发模式、反射机制、映射、UUID、邮件的发送、动态的获取本机的ip地址、数据库的操作。在进行数据库操作前一定不要忘记先进行数据库的连接。
|