【手把手】JavaWeb 入門級項目實戰 -- 文章發布系統 (第四節)


首先,更正一下上一章中的一個小錯誤,就是在index.jsp中,banner部分沒有添加結束的標簽,加上去就OK了,我也是完善頁面的時候發現的。

另外,index.jsp中引入的jQuery也需要換成本地的。

<script src="${basePath}/static/js/jQuery.js"></script>

今天我把頁面重構了一下,添加了內容區和底欄(footer),我會把目前的代碼上傳的,有需要的自己去看就行了,我們就不在前台頁面花費太多的時間了。div + css,布局等等,這些東西以后有時間的話,我單獨開貼分享吧。

都已經寫了三篇文章了,還沒有寫Java代碼,實在有些說不過去。

1. 登陸頁面

登陸頁我已經寫好了,現在看看效果,簡單說明一下。

點擊登陸按鈕,可以跳轉到登陸頁面。

登陸按鈕就是一個超鏈接。

JSP頁面就是一個servlet,但是省去了很多寫Servlet的麻煩,login.jsp已經寫好了,就放在WebContent目錄下。

昨天憋了一上午,總算寫好了登陸頁面。我不是專業做前端的,所以只做了一個大概樣子。用了很多css3的屬性,所以IE678上瀏覽的效果是不好的。

關於這個頁面,今天我調整了一下,不想搞得那么復雜了,我去掉了所有的圖標和飄動白雲,關於css特效,h5的話呢,以后單獨拿出來說明吧,畢竟好多人都反應說太花哨了,因為是入門級的小項目,我也不想弄得那么復雜了。

雖然頁面單調了些,不過對於初學者來說,相對來說比較好理解。之前的頁面的確有點太花哨了,還弄了幾朵雲飄來飄去的,說不定還影響性能,所以我把這些都去掉了。

2. 新的目錄結構

之前的代碼有很多冗余的地方,比如標題欄,每個頁面都需要寫一遍。而且js和css都是寫在本頁面的。實際開發一般都不會這么做。所以,我把這些東西都分離出來了,放在各自的目錄里。

以下是新的目錄結構:

header.jsp


<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<div class="header">
	<div class='logo'>原創文字</div>
	<ul>
		<li class='first'><a href="index.jsp">首頁</a></li>
		<li class='item'><a href="javascript:void(0)">原創故事</a></li>
		<li  class='item'><a href="javascript:void(0)">熱門專題</li>
		<li  class='item'><a href="javascript:void(0)">欣賞美文</li>
		<li  class='item'><a href="javascript:void(0)">贊助</a></li>
	</ul>
	
	<div class='login'>
		<span><a href="login.jsp">登陸</a></span>  
		<span>|</span> 
		<span><a href="javascript:void(0)">注冊</a></span>
	</div>
</div>

這就是標題欄,以后新增的jsp頁面,只需要把這個header.jsp引入就可以了。注意,這種引入就相當於把里面的代碼原封不動地拷貝進去,所以如果用相對路徑引用資源文件,就還是以原本的頁面為准。

引入方式:

<!-- 頭部頁面 -->
<%@include file="common/header.jsp" %>

footer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<div class='footer'>
	免責聲明:本站所有素材均來自網絡,僅供學習交流。如果侵犯了您的權益,請聯系我,我會第一時間刪除侵權內容。
</div>

taglib.jsp (一些公共的配置等)


<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
	String path = request.getContextPath();
	int port = request.getServerPort();
	String basePath  = null;
	if(port==80){
		basePath = request.getScheme()+"://"+request.getServerName()+path;
	}else{
		basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
	}
	request.setAttribute("basePath", basePath);
%>

basePath 就是項目的根路徑。這樣做的好處就是,使得JSP看起來很干凈,沒有那么多冗余的代碼了。

大概就是這個樣子,接下來,我們開始寫業務。

3. 登陸功能的MVC流程

登陸框中,目前只有用戶名和密碼這兩個選項。

我們首先要做的就是將這兩個值傳遞到后台。所謂的后台,其實就是Java代碼。為了看起來比較清晰,我們在WebContent目錄下新建一個controller包。

這是一個MVC分層的示意圖

意思就是說,用戶登錄之后,我們需要驗證它的用戶名和密碼是否正確,那么就需要將數據拿到數據庫里面去匹配。總體的流程大概是這樣:我先在前台獲取用戶名和密碼,然后到controller層(控制層),這一層需要接受你傳過來的用戶名和密碼,進行一些基本的控制。

然后繼續將數據傳遞到service層,也就是業務層,這一層會根據具體的業務對你的數據進行判斷和分析,最后,才傳遞到dao層,這一層原則上就是和數據庫進行交互的。多半是寫sql語句然后操作數據庫。

就比如說用戶登錄這個功能,我需要判斷的就是

  1. 你這個用戶是否存在?
  2. 用戶名和密碼是否正確?

最終,還需要將登錄的標志返回給前台。

dao -> servide -> controller -> JSP

這樣就是一個完整的流程。

4. 從JSP到controller層

讓我們打開login.jsp頁面,引入jQuery

<script src="${basePath}/static/js/jQuery.js"></script>

登錄框的HTML代碼:


<!-- 登陸框 -->
<div class='content'>
	<div class='logo'><i style='font-size:90px;' class="iconfont icon-denglu"></i></div>
	<div class='inputBox mt50 ml32'>
		<input type="text" id="username" autofocus="autofocus" autocomplete="off" maxlength="60" placeholder="請輸入賬號/郵箱/手機號">
		<i style='font-size:20px;margin-left:-32px;opacity:0.8;' class='iconfont icon-yonghuming'></i>
	</div>
	<div class='inputBox mt50 ml32'>
		<input type="password" id="password" autofocus="autofocus" autocomplete="off" maxlength="60" placeholder="請輸入密碼">
		<i style='font-size:20px;margin-left:-32px;opacity:0.8;' class='iconfont icon-mima'></i>
	</div>
	
	<div class='mt50 ml32'>
		<button class="login_btn" onclick="#">登陸</button>
	</div>
</div>

我們在下面寫一個script塊,js代碼就全部寫在這里。

給登陸按鈕綁定一個點擊事件:

<div class='mt50 ml32'>
        <button class="login_btn" onclick="login()">登陸</button>
</div>

登陸方法

function login(){
	var username = $('#username').val();
	var password = $('#password').val();
	alert(username + "," + password);
}

當成功alert出來數據后,說明到此為止的代碼是正確的。

接下來,利用jQuery的ajax方法,將數據提交到controller層。


function login(){
	var username = $('#username').val();
	var password = $('#password').val();
	$.ajax({
		type:"post",//請求方式
		url:"${basePath}/controller/loginController.jsp",//請求地址
		data:{"username":username,"password":password},//傳遞給controller的json數據
		error:function(){
			alert("登陸出錯!");
		},
		success:function(data){ //返回成功執行回調函數。
			
		}
	});
	
}

我已經都寫好注釋了,ajax方法在web開發過程中,是被普遍使用的。

新建一個loginController.jsp ,這就是所謂的服務器端。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%

	//設置請求的編碼
	//request.setCharacterEncoding("UTF-8");
	//獲取客戶端傳遞過來參數
	String username = request.getParameter("username");
	String password = request.getParameter("password");
	System.out.println(username);
	System.out.println(password);
	//如果用戶名和密碼不為空
	
%>

從JSP頁面到controller,用戶名和密碼是被裝在一個叫做request的變量中,它其實也就相當於一個json,一個map,都是差不多的東西,這里就不詳細說明了。當然了,他也是JSP九大隱式對象中的一員。

Paste_Image.png

我們來測試一下,點擊登陸按鈕。

成功了!可以看到數據已經成功傳遞到controller層了。

因為我們還沒有數據表和JavaBean,所以我們先不急着寫service層,先開始編寫JavaBean吧。

5. 從JavaBean到數據庫表。

我們在src目錄下新建一個存放JavaBean的包

關於JavaBean,如果不是很了解的話,可以看看這篇文章:

http://www.cnblogs.com/skyblue-li/p/5900216.html

一個記錄用戶信息的JavaBean,我想了以下這些屬性:

private String id;	  //主鍵,采用UUID
private String username;  //用戶名
private String password;  //密碼
private String headerPic; //頭像
private String email;	  //電子郵箱
private Integer male;	  //性別 0男 1女 3保密
private String createTime;//創建時間
private String updateTime;//最后更新時間
private Integer isDelete; // 刪除狀態0未刪除1刪除
private String address;   //地址
private String telephone; //電話

當你的JavaBean設計好了,差不多對應的數據庫表也就出來了。

之前寫過一篇關於注解的文章:

http://www.cnblogs.com/skyblue-li/p/5900228.html

現在可以用這個知識點做點有趣的事情了,比如將一個JavaBean轉換成建表語句。

新建一個注解包,里面添加兩個注解

column.java

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD) 		//注解的目標
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	
	public String field() ;	//字段名稱
	public boolean primaryKey() default false;//是否為主鍵
	public String type() default "VARCHAR(80)";//字段類型
	public boolean defaultNull() default true; //是否允許為空
	
}

Table.java

package annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) 		//注解的目標是類
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

	public String tableName();
}

我們創建了兩個注解。

接下來,在util包(也就是工具包)中新建兩個工具類

StringUtils 字符串工具類

package util;


public class StringUtils {
	
	public static boolean isEmpty(String str) {
		return null == str  || str.equals("")
				|| str.matches("\\s*");
	}

	public static String defaultValue(String content,String defaultValue){
		if(isEmpty(content)){
			return defaultValue;
		}
		return content;
	}
}

isEmpty的作用是判斷字符串是否為空。
defaultValue表示給字符串設置默認值,有點類似於oracle數據庫中的nvl語法。

TableUtils 數據表工具類

package util;

import java.lang.reflect.Field;

import annotation.Column;
import annotation.Table;

public class TableUtils {
	
	
	public static String getCreateTableSQl(Class<?> clazz){
		StringBuilder sb = new StringBuilder();
		sb.append("create table ");
		//獲取表名
		Table table = (Table) clazz.getAnnotation(Table.class);
		String tableName = table.tableName();
		sb.append(tableName).append("(\n");
		
		Field[] fields = clazz.getDeclaredFields();
		String primaryKey = "";
		//遍歷所有字段
		for (int i = 0; i < fields.length; i++) {
			Column column = (Column) fields[i].getAnnotations()[0];
			String field = column.field();
			String type = column.type();
			boolean defaultNull = column.defaultNull();
			
			sb.append("\t" + field).append(" ").append(type);
			if(defaultNull){
				if(type.toUpperCase().equals("TIMESTAMP")){
					sb.append(",\n");
				}else{
					sb.append(" DEFAULT NULL,\n");
				}
			}else{
				sb.append(" NOT NULL,\n");
				if(column.primaryKey()){
					primaryKey = "PRIMARY KEY ("+field+")";
				}
			}
		}
		
		if(!StringUtils.isEmpty(primaryKey)){
			sb.append("\t").append(primaryKey);
		}
		sb.append("\n) DEFAULT CHARSET=utf8");
		
		return sb.toString();
	}
	
}

getCreateTableSQl方法是利用反射和注解有關的知識,給一個JavaBean自動生成建表語句,目前只支持MySQL,因為這方面的知識我也是剛開始學,寫得不好的地方還請各位多多包涵。

接下來,給JavaBean添加注解。

@Table(tableName = "t_user")
public class User{
   //屬性
}

屬性如下:

@Column(type = "varchar(30)" ,field = "id" ,primaryKey = true ,defaultNull = false)
private String id;		  //主鍵,采用UUID

@Column(type = "VARCHAR(20)", field = "username")
private String username;  //用戶名

@Column(type = "VARCHAR(20)", field = "password")
private String password;  //密碼

@Column(type = "VARCHAR(60)", field = "headerPic")
private String headerPic; //頭像

@Column(type = "VARCHAR(60)", field = "email")
private String email;	  //電子郵箱

@Column(type = "VARCHAR(2)", field = "sex")
private Integer sex;	  //性別 0男 1女 3保密

@Column(type = "datetime", field = "create_time")
private String createTime;//創建時間

@Column(type = "timestamp", field = "update_time")
private String updateTime;//最后更新時間

@Column(type = "int(1)", field = "is_delete")
private Integer isDelete; // 刪除狀態  0未刪除  1刪除

@Column(type = "VARCHAR(200)", field = "address")
private String address;   //地址

@Column(type = "VARCHAR(15)", field = "telephone")
private String telephone; //電話

創建一個測試包和測試類:

package test;

import bean.User;
import util.TableUtils;

public class TestMain {
	public static void main(String[] args) {
		String sql = TableUtils.getCreateTableSQl(User.class);
		System.out.println(sql);
	}
}

運行

OK,拿到sql語句了。

我已經安裝了mysql,用root用戶登陸后,新建一個database

使用這個database

將剛才得到的sql語句復制進去,加分號,回車。

這就表明數據庫表已經建好了,默認編碼是UTF-8。

本文結束。

最后說一下更新的問題,最近事情比較多,無奈改為周更了,正常情況下每周日定時更新。至於源碼,我還沒有放到github上,打算以后寫得差不多了再發布吧。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM