1. 程式人生 > >java實現郵箱註冊驗證

java實現郵箱註冊驗證

在日常生活中,我們在一個網站中註冊一個賬戶時,往往在提交個人資訊後,網站還要我們通過手機或郵件來驗證,郵件的話大概會是下面這個樣子的:

使用者通過點選連結從而完成註冊,然後才能登入。

也許你會想,為什麼要這麼麻煩直接提交註冊不就行了嗎?這其中很大一部分原因是為了防止惡意註冊。接下來讓我們一起來使用最簡單的JSP+Servlet的方式來完成一個通過郵箱驗證註冊的小案例吧。

準備工作

前提知識

動手實踐之前,你最好對以下知識有所瞭解:

  • JSP和Servlet
  • Maven
  • MySQL
  • c3p0

如果對郵件收發過程完全不瞭解的話,可以花三分鐘的時間到慕課網瞭解一下,講得算是非常清楚了,這裡就不贅述了。放張圖回憶一下:

郵箱準備

在瞭解的上述內容之後,要實現這個案例,首先我們還得有兩個郵箱賬號,一個用來發送郵件,一個用來接收郵件。本案例使用QQ郵箱向163郵箱傳送啟用郵件,因此需要登入QQ郵箱,在設定->賬戶面板中開啟POP3/SMTP服務,以允許我們通過第三方客戶端傳送郵件:

 

還要注意的是,登入以下服務: POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服務時,需要用到授權碼而不是QQ密碼,授權碼是用於登入第三方郵件客戶端的專用密碼。因此我們需要獲得授權碼,以在後面的程式中使用。

好了,到此準備工作就差不多了,下面開始動手吧。

實現註冊Demo

建立Maven工程

本次案例基於Maven,因此你要先建立一個Maven的Web工程,並引入相關依賴:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

<dependencies>

<!-- JavaEE依賴 -->

<dependency>

<groupId>javaee</groupId>

<artifactId>javaee-api</artifactId>

<version>5</version>

<scope>test</scope>

</dependency>

<dependency>

<groupId>taglibs</groupId>

<artifactId>standard</artifactId>

<version>1.1.2</version>

</dependency>

<!-- mysql驅動依賴 -->

<dependency>

<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<version>5.1.40</version>

</dependency>

<!-- c3p0依賴 -->

<dependency>

<groupId>c3p0</groupId>

<artifactId>c3p0</artifactId>

<version>0.9.1.2</version>

</dependency>

<!-- JavaMail相關依賴 -->

<dependency>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

<version>1.4.7</version>

</dependency>

<dependency>

<groupId>javax.activation</groupId>

<artifactId>activation</artifactId>

<version>1.1.1</version>

</dependency>

</dependencies>

建立資料庫表

接下來使用MySQL建立一張簡單的使用者表:

1

2

3

4

5

6

7

8

create table `user`(

id int(11) primary key auto_increment comment '使用者id',

username varchar(255) not null comment '使用者名稱',

email varchar(255) not null comment '使用者郵箱',

password varchar(255) not null comment '使用者密碼',

state int(1) not null default 0 comment '使用者啟用狀態:0表示未啟用,1表示啟用',

code varchar(255) not null comment '啟用碼'

)engine=InnoDB default charset=utf8;

其中要注意的地方是state欄位(用來判斷使用者賬號是否啟用)和code欄位(啟用碼)。

建立註冊頁面

使用JSP建立一個最簡單的註冊頁面(請自行忽略介面):

嗯,果然夠簡單。

主要的業務邏輯

先想一下,我們的整個流程應該是這樣的:

  1. 使用者填寫相關資訊,點選註冊按鈕
  2. 系統先將使用者記錄儲存到資料庫中,其中使用者狀態為未啟用
  3. 系統傳送一封郵件並通知使用者去驗證
  4. 使用者登入郵箱並點選啟用連結
  5. 系統將使用者狀態更改為已啟用並通知使用者註冊成功

搞清楚了整個流程,實現起來應該就不難了。下圖是我建立的包結構:

ps:完整程式碼請見後文連結,這裡只討論主要的思路

首先是,使用者提交註冊資訊後,相應的servlet會將相關資訊傳給service層去處理,在service中需要做的就是講記錄儲存到資料庫中(呼叫dao層),然後再給使用者傳送一封郵件,UserServiceImpl相關程式碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

public boolean doRegister(String userName, String password, String email) {

// 這裡可以驗證各欄位是否為空

//利用正則表示式(可改進)驗證郵箱是否符合郵箱的格式

if(!email.matches("^\\[email protected](\\w+\\.)+\\w+$")){

return false;

}

//生成啟用碼

String code=CodeUtil.generateUniqueCode();

User user=new User(userName,email,password,0,code);

//將使用者儲存到資料庫

UserDao userDao=new UserDaoImpl();

//儲存成功則通過執行緒的方式給使用者傳送一封郵件

if(userDao.save(user)>0){

new Thread(new MailUtil(email, code)).start();;

return true;

}

return false;

}

需要注意的是,應該新建一個執行緒去執行傳送郵件的任務,不然被罵估計是免不了了。 資料庫的操作比較簡單,此處就不貼出來了,無非是將使用者記錄插到資料庫中。值得一提的是,此處使用c3p0來作為資料來源來替代DriverManager,在頻繁獲取釋放資料庫連線時效率會大大提高,c3p0最簡單的配置如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

<?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>

<named-config name="mysql">

<property name="driverClass">com.mysql.jdbc.Driver</property>

<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/test1?useSSL=false</property>

<property name="user">root</property>

<property name="password">123456</property>

<!-- 初始化時一個連線池嘗試獲得的連線數量,預設是3,大小應該在maxPoolSize和minPoolSize之間 -->

<property name="initialPoolSize">5</property>

<!-- 一個連線最大空閒時間(單位是秒),0意味著連線不會過時 -->

<property name="maxIdleTime">30</property>

<!-- 任何指定時間的最大連線數量 ,預設值是15 -->

<property name="maxPoolSize">20</property>

<!-- 任何指定時間的最小連線數量 ,預設值是3 -->

<property name="minPoolSize">5</property>

</named-config>

</c3p0-config>

提供一個工具類DBUtil以獲取,釋放連線:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

public class DBUtil {

private static ComboPooledDataSource cpds=null;

static{

cpds=new ComboPooledDataSource("mysql");

}

public static Connection getConnection(){

Connection connection=null;

try {

connection = cpds.getConnection();

catch (SQLException e) {

e.printStackTrace();

}

return connection;

}

public static void close(Connection conn,PreparedStatement pstmt,ResultSet rs){

try {

if(rs!=null){

rs.close();

}

if(pstmt!=null){

pstmt.close();

}

if(rs!=null){

rs.close();

}

catch (SQLException e) {

e.printStackTrace();

}

}

}

要特別注意的一點是:即使是使用連線池,使用完Connection後呼叫close方法,當然這不意味著關閉與資料庫的TCP 連線,而是將連線還回到池中去,如果不close掉的話,這個連線將會一直被佔用,直到連線池中的連線耗盡為止。

使用JavaMail傳送郵件

使用JavaMail傳送郵件非常簡單,也是三步曲:

  1. 建立連線物件javax.mail.Session
  2. 建立郵件物件 javax.mail.Message
  3. 傳送郵件

直接看程式碼,詳細的註釋在程式碼中,MailUtil程式碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

public class MailUtil implements Runnable {

private String email;// 收件人郵箱

private String code;// 啟用碼

public MailUtil(String email, String code) {

this.email = email;

this.code = code;

}

public void run() {

// 1.建立連線物件javax.mail.Session

// 2.建立郵件物件 javax.mail.Message

// 3.傳送一封啟用郵件

String from = "[email protected]";// 發件人電子郵箱

String host = "smtp.qq.com"// 指定傳送郵件的主機smtp.qq.com(QQ)|smtp.163.com(網易)

Properties properties = System.getProperties();// 獲取系統屬性

properties.setProperty("mail.smtp.host", host);// 設定郵件伺服器

properties.setProperty("mail.smtp.auth""true");// 開啟認證

try {

//QQ郵箱需要下面這段程式碼,163郵箱不需要

MailSSLSocketFactory sf = new MailSSLSocketFactory();

sf.setTrustAllHosts(true);

properties.put("mail.smtp.ssl.enable""true");

properties.put("mail.smtp.ssl.socketFactory", sf);

// 1.獲取預設session物件

Session session = Session.getDefaultInstance(properties, new Authenticator() {

public PasswordAuthentication getPasswordAuthentication() {

return new PasswordAuthentication("[email protected]""xxx"); // 發件人郵箱賬號、授權碼

}

});

// 2.建立郵件物件

Message message = new MimeMessage(session);

// 2.1設定發件人

message.setFrom(new InternetAddress(from));

// 2.2設定接收人

message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));

// 2.3設定郵件主題

message.setSubject("賬號啟用");

// 2.4設定郵件內容

String content = "<html><head></head><body><h1>這是一封啟用郵件,啟用請點選以下連結</h1><h3><a href='http://localhost:8080/RegisterDemo/ActiveServlet?code="

+ code + "'>http://localhost:8080/RegisterDemo/ActiveServlet?code=" + code

"</href></h3></body></html>";

message.setContent(content, "text/html;charset=UTF-8");

// 3.傳送郵件

Transport.send(message);

System.out.println("郵件成功傳送!");

catch (Exception e) {

e.printStackTrace();

}

}

}

ps:需要把上面的賬號、授權碼進行相應修改。

完成後,再有使用者提交註冊資訊時,應該就能收到驗證郵件了:

使用者點選連結後,我們要做的工作就是根據code(可以利用UUID生成)更改資料庫中相應使用者的狀態,然後提示使用者註冊結果了。

總結

簡單介紹瞭如何使用JavaMail完成了一個帶郵箱驗證的註冊案例,當然在實際開發中還有許多細節要注意,例如對使用者提交資訊的校驗,密碼進行加密等,此處的簡單案例並未詳盡處理這些細節。

注:想要讓別人能夠成功的完成註冊,需要提供一個公網ip,替換掉localhost