1. 程式人生 > >javaweb登陸註冊驗證碼的顯示生成(在第一次載入頁面的時候,sesson中的驗證碼總是為空)

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下面會有這種問題還沒弄清楚。希望瞭解的人能教一教。