javaweb登陸註冊驗證碼的顯示生成(在第一次載入頁面的時候,sesson中的驗證碼總是為空)
問題描述:在寫一個登陸介面的時候用到了驗證碼,產生的問題在於使用myeclipse第一次載入index.jsp(我的登陸介面)的時候驗證總是失敗,重新整理一次後驗證成功,或者在第一次進入index.jsp頁面手動重新整理。這就很讓人討厭了。
問題的原因:經過除錯後發現,第一從開啟index.jsp頁面成功的顯示出來了驗證碼圖片,但是伺服器在生成圖片時候儲存在Session的驗證碼文字為空。導致與使用者輸入的驗證碼匹配不成功。
驗證碼部分的具體程式碼
index.jsp。(前端用到了bootstrap框架,可以忽略,重點在紅色部分)
<html> <head> <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <link rel="stylesheet" href="http://cdn.static.runoob.com/libs/bootstrap/3.3.7/css/bootstrap.min.css"> <!-- 點選重新整理頁面 --> <script type="text/javascript"> function refreshImage(obj) { obj.src = "image?randNum=" + Math.random(); } </script></head>
<body> <div> <div class="col-md-12"> <div class="form-bg"> form action="login" class="form-horizontal"> <!-- <span class="heading">使用者登入</span> --> <div class="form-group"> <input type="text" class="form-control" name="userName" id="userName" placeholder="使用者名稱"> </div> <div class="form-group help"> <input type="password" class="form-control" name="password" id="password" placeholder="密 碼"> </div> <div class="form-group"> <!-- 驗證碼驗證 --> <span> <input type="text" class="userCode" name="userCode" id="userCode" placeholder="驗證碼 " style="float:left;width:90px"> <img alt="看不清,點選更換" src="image" onclick="refreshImage(this)"
style="cursor:hand;background-color:#999;right;margin-right:10px;width:80px;height:30px"> </span> </div> <div class="form-group"> <div class="main-checkbox"> <input type="checkbox" value="None" id="checkbox1" name="check" /> <label for="checkbox1"></label> </div> <span class="text">Remember me</span> <button type="submit" class="btn btn-default">登入</button> </div> <div style="font-size: 12"> <a href="">忘記密碼?</a><a href="student/register.jsp"> 註冊</a> </div> </form> </div> </div> </div></body>
執行結果:
後端使用struts2,如果你沒有使用框架直接使用servlet處理。那麼ImageAction的execute()對應servletdepost()或者get()方法就行。
其中紅色的 <img src="image">中的image為action的name,用於匹配後臺ImageAction.java。
對應strutx.xml
<struts>
<!-- 在這裡設定字元編碼,防止亂碼 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<package name="default" extends="struts-default">
<!--其他省略-->
<action name="image" class="com.liang.action.ImageAction">
</action>
</package>
</struts>
com.liang.action包下的ImageAction.java檔案,處理驗證碼事務
public class ImageAction extends ActionSupport {
public String execute() {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
//生成一個驗證碼類,包括圖片以及文字
VerificationCodeDao vc = new VerificationCodeDao();
BufferedImage image = vc.getImage(); // 獲取驗證碼圖片
request.getSession().setAttribute("verificationCode", vc.getText()); // 將驗證碼的文字存在session中。用於驗證
try {
VerificationCodeDao.output(image, response.getOutputStream());// 將驗證碼圖片響應給客戶端
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*必須設成null返回,不能使用常規的String型別,否則雖然能正常輸出顯示但是後臺報錯會*/
return null;
}
}
順便提一下:這裡有之前遇到的另一個問題,就是首次載入或者點選重新整理呼叫後臺的action處理時返回值不能使用String型別,否則後臺會報 getOutputStream() has already been called for this response的錯誤。因為沒有返回值,可以看到我的strts.xml檔案中<action>標籤下面沒有<result name="...">...jsp</result>標籤
ImageAction.java中的驗證碼類VerifivationCodeDao.java。生成驗證碼的程式碼很多,這段程式碼是在網上copy的。
public class VerificationCodeDao {
private int weight = 80; // 驗證碼圖片的長和寬
private int height = 30;
private String text; // 用來儲存驗證碼的文字內容
private Random random = new Random(); // 獲取隨機數物件
private String[] fontNames = { "宋體", "華文楷體", "黑體", "微軟雅黑", "楷體_GB2312" }; // 字型陣列
private String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ"; // 驗證碼陣列
/**
* 獲取隨機的顏色
* @return Color(r,g,b)
*/
private Color randomColor() {
int r = this.random.nextInt(200); // 這裡為什麼是150,因為當r,g,b都為255時,即為白色,為了好辨認,需要顏色深一點。
int g = this.random.nextInt(200);
int b = this.random.nextInt(200);
return new Color(r, g, b); // 返回一個隨機顏色
}
/**
* @param start:
* @param end:
* @return
*/
private Color getColor(int start,int end){
int r=start+this.random.nextInt(end-start);
int g=start+this.random.nextInt(end-start);
int b=start+this.random.nextInt(end-start);
return new Color(r,g,b);
}
private Font randomFont() // 獲取隨機字型
{
int index = random.nextInt(fontNames.length); // 獲取隨機的字型
String fontName = fontNames[index];
int style = random.nextInt(4); // 隨機獲取字型的樣式,0是無樣式,1是加粗,2是斜體,3是加粗加斜體
int size = random.nextInt(5) + 24; // 隨機獲取字型的大小
return new Font(fontName, style, size); // 返回一個隨機的字型
}
private char randomChar() // 獲取隨機字元
{
int index = random.nextInt(codes.length());
return codes.charAt(index);
}
private void drawLine(BufferedImage image) // 畫干擾線,驗證碼干擾線用來防止計算機解析圖片
{
int num = 5; // 定義干擾線的數量
//獲取指向該影象上的Graphic畫筆
Graphics2D g = (Graphics2D) image.getGraphics();
for (int i = 0; i < num; i++) {
int x1 = random.nextInt(weight);
int y1 = random.nextInt(height);
int x2 = random.nextInt(weight);
int y2 = random.nextInt(height);
g.setColor(getColor(0,180));
g.drawLine(x1, y1, x2, y2);
}
}
private BufferedImage createImage() // 建立圖片
{
BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB); // 建立圖片緩衝區
Graphics2D g = (Graphics2D) image.getGraphics(); // 獲取畫筆
g.setColor(getColor(150, 255)); // 設定背景色
g.fillRect(0, 0, weight, height);
return image; // 返回一個圖片
}
public BufferedImage getImage() // 獲取驗證碼圖片的方法
{
BufferedImage image = createImage();
Graphics2D g = (Graphics2D) image.getGraphics(); // 獲取畫筆
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 4; i++) // 畫四個字元即可
{
String s = randomChar() + ""; // 隨機生成字元,因為只有畫字串的方法,沒有畫字元的方法,所以需要將字元變成字串再畫
sb.append(s); // 新增到StringBuilder裡面
float x = i * 1.0F * weight / 4; // 定義字元的x座標
g.setFont(randomFont()); // 設定字型,隨機
g.setColor(getColor(0,180)); // 設定顏色,隨機
g.drawString(s, x, height - 5);
}
this.text = sb.toString();
drawLine(image);
return image;
}
public String getText() // 獲取驗證碼文字的方法
{
return text;
}
public static void output(BufferedImage image, OutputStream out) throws IOException // 將驗證碼圖片寫出的方法
{
ImageIO.write(image, "JPEG", out);
}
}
關於驗證碼第一次載入的時候session中的驗證碼文字為空的解決辦法,就是載入頁面的時候主動呼叫y一次後臺的imageAction.java來重新整理一下session中的驗證碼。這裡給大家找了一個連結參考http://younglibin.iteye.com/blog/469470
不過後來驚奇的發現第一次session為空 只是在myeclipse下開啟網頁會出現。
如果是使用瀏覽器開啟。如第一次在chrome下面輸入http://localhost/TestSystem/index.jsp(我的本地連結)開啟,session內容不為空。不會有問題。具體為什麼myeclipse下面會有這種問題還沒弄清楚。希望瞭解的人能教一教。