基于Servlet實(shí)現(xiàn)技術(shù)問答網(wǎng)站系統(tǒng)
這一篇博客將詳細(xì)介紹一個(gè)基于Servlet的問答網(wǎng)站的實(shí)現(xiàn),有詳細(xì)的代碼。
可能篇幅較長,以代碼為主,有興趣的童鞋看完可以嘗試動(dòng)手搭建一個(gè)屬于自己的問答社區(qū)。
工具:Eclipse,數(shù)據(jù)庫用到了MySQL,這次項(xiàng)目中未使用jsp,全部以Servlet注解的方式連接HTML和Servlet,JDK最好使用1.8,tomcat使用8.0。(注解方式為JDK1.5后的特性,最低要求1.5+,本項(xiàng)目使用JDK1.8)。
在這篇博客中可以學(xué)習(xí)到:
1,Servlet中關(guān)于注解的使用,本項(xiàng)目沒有使用到傳統(tǒng)的Servlet配置web.xml,全部使用注解的形式。
2,了解Font Awesome這一矢量圖標(biāo)庫的使用,他基本提供了項(xiàng)目中所要使用到的所有圖標(biāo),方便,快捷。
3,了解simditor這一富文本編輯器的使用,網(wǎng)站中直接嵌入富文本編輯器,再也不用為讀取出來的文字格式不對發(fā)愁了。
4,關(guān)于項(xiàng)目中如何加入驗(yàn)證碼,數(shù)據(jù)庫查詢之前先進(jìn)行驗(yàn)證碼驗(yàn)證。
5,關(guān)于MVC框架顯示層——Velocity技術(shù)的使用。
先看一下大體項(xiàng)目圖(由于主要做后臺(tái),前臺(tái)可能略丑,大家可以自行找網(wǎng)站模板)
登錄界面:

注冊界面:

首頁,展示了大家的提問:

解答界面,點(diǎn)擊別人的提問后進(jìn)入解答界面,使用了富文本編輯器。

我的解答界面,展示了我回答的歷史:

我的提問界面,展示了我提問的所有問題:

提問界面:進(jìn)入網(wǎng)站點(diǎn)擊我要提問,加入當(dāng)前頁編輯問題:

下面介紹主要代碼(代碼中加入了詳細(xì)注釋,所以不再做說明)
主頁列表Servlet:
@WebServlet( "/list.do" )
public class ListServlet extends HttpServlet {
private static final long serialVersionUID = 810339694607399128L;
@Override
protected void service( HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {
String question=request.getParameter("quest");
System.out.println(question);
if(StringHelper.notEmpty(question)){
final String SQL = "SELECT id , title ,content, publish_time , publish_ip , user_id FROM t_topic where title =? " ;
ResultSet rs = JdbcHelper.query( SQL,question );
// 創(chuàng)建一個(gè) List 對象,用來保存一批 Topic 對象
final List<Topic> topics = new ArrayList<>();
try {
// 每循環(huán)一次,光標(biāo)下移一行,如果該行有數(shù)據(jù)返回 true
while( rs.next() ){
Topic t = new Topic(); // 創(chuàng)建對象
t.setId( rs.getInt( 1 ) ); // 將 結(jié)果集 中的 該行數(shù)據(jù) 封裝到 t 對象的 id 屬性中
t.setTitle( rs.getString( 2 ) );
t.setContent(rs.getString(3));
t.setPublishTime( rs.getTimestamp( 4 ));
t.setPublishIp( rs.getString( 5 ) );
User u = new User(); // 創(chuàng)建 一個(gè) User 對象
u.setId( rs.getInt( 6 ) ); // 將 t_topic 表中的 user_id 放入到 User 對象的 id 屬性中
t.setUser( u ); // 將 User 對象 設(shè)置到 Topic 對象上
/** 將 本次循環(huán) 創(chuàng)建的對象(已經(jīng)封裝數(shù)據(jù)) 添加到 List 集合中 */
topics.add( t );
}
} catch (SQLException e) {
e.printStackTrace();
}
JdbcHelper.release( rs ); // 關(guān)閉 結(jié)果集,釋放相關(guān)的資源
/**** 為每個(gè)問題尋找提問者 ***********************************/
//for( int i = 0 ; i < topics.size() ; i++ ){
for( int i = 0 , len = topics.size() ; i < len ; i++ ){
Topic t = topics.get( i ) ; // 獲得 題目
User u = t.getUser(); // 獲得當(dāng)前題目的User對象 ( 該對象中只有 id 沒有其它數(shù)據(jù) )
// 根據(jù) 用戶對象的 id 來查詢 用戶的信息
String querySQL = "SELECT id , username , password FROM t_user WHERE id = ? " ;
ResultSet userRs = JdbcHelper.query( querySQL , u.getId() );
try {
if( userRs.next() ) { // 如果查詢到用戶信息
// 注意,這里應(yīng)該使用 userRs
u.setUsername( userRs.getString( 2 ) ); // 將 username 列的值設(shè)置到 用戶對象的 username 屬性中
u.setPassword( userRs.getString( 3 )); // 將 password 列的值設(shè)置到 用戶對象的 password 屬性中
}
} catch (SQLException e) {
e.printStackTrace();
}
JdbcHelper.release( userRs ); // 關(guān)閉 結(jié)果集,釋放相關(guān)的資源
}
ServletContext application = request.getServletContext();
/** 將這些數(shù)據(jù)保存到 application **/
application.setAttribute( "topics" , topics );
System.out.println( "問題列表: " + topics );
// 去 list.html 頁面
response.sendRedirect( request.getContextPath() + "/list.html");
}else{
/**** 查詢數(shù)據(jù)庫中的所有問題 ***********************************/
final String SQL = "SELECT id , title ,content ,publish_time , publish_ip , user_id FROM t_topic ORDER BY publish_time DESC" ;
ResultSet rs = JdbcHelper.query( SQL );
// 創(chuàng)建一個(gè) List 對象,用來保存一批 Topic 對象
final List<Topic> topics = new ArrayList<>();
try {
// 每循環(huán)一次,光標(biāo)下移一行,如果該行有數(shù)據(jù)返回 true
while( rs.next() ){
Topic t = new Topic(); // 創(chuàng)建對象
t.setId( rs.getInt( 1 ) ); // 將 結(jié)果集 中的 該行數(shù)據(jù) 封裝到 t 對象的 id 屬性中
t.setTitle( rs.getString( 2 ) );
t.setContent(rs.getString(3));
t.setPublishTime( rs.getTimestamp( 4 ));
t.setPublishIp( rs.getString( 5 ) );
User u = new User(); // 創(chuàng)建 一個(gè) User 對象
u.setId( rs.getInt( 6) ); // 將 t_topic 表中的 user_id 放入到 User 對象的 id 屬性中
t.setUser( u ); // 將 User 對象 設(shè)置到 Topic 對象上
/** 將 本次循環(huán) 創(chuàng)建的對象(已經(jīng)封裝數(shù)據(jù)) 添加到 List 集合中 */
topics.add( t );
}
} catch (SQLException e) {
e.printStackTrace();
}
JdbcHelper.release( rs ); // 關(guān)閉 結(jié)果集,釋放相關(guān)的資源
/**** 為每個(gè)問題尋找提問者 ***********************************/
//for( int i = 0 ; i < topics.size() ; i++ ){
for( int i = 0 , len = topics.size() ; i < len ; i++ ){
Topic t = topics.get( i ) ; // 獲得 題目
User u = t.getUser(); // 獲得當(dāng)前題目的User對象 ( 該對象中只有 id 沒有其它數(shù)據(jù) )
// 根據(jù) 用戶對象的 id 來查詢 用戶的信息
String querySQL = "SELECT id , username , password FROM t_user WHERE id = ? " ;
ResultSet userRs = JdbcHelper.query( querySQL , u.getId() );
try {
if( userRs.next() ) { // 如果查詢到用戶信息
// 注意,這里應(yīng)該使用 userRs
u.setUsername( userRs.getString( 2 ) ); // 將 username 列的值設(shè)置到 用戶對象的 username 屬性中
u.setPassword( userRs.getString( 3 )); // 將 password 列的值設(shè)置到 用戶對象的 password 屬性中
}
} catch (SQLException e) {
e.printStackTrace();
}
JdbcHelper.release( userRs ); // 關(guān)閉 結(jié)果集,釋放相關(guān)的資源
}
ServletContext application = request.getServletContext();
/** 將這些數(shù)據(jù)保存到 application **/
application.setAttribute( "topics" , topics );
System.out.println( "問題列表: " + topics );
// 去 list.html 頁面
response.sendRedirect( request.getContextPath() + "/list.html");
}
}
}
主頁列表顯示界面代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>首頁</title>
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/wen.css">
</head>
<body>
## 登錄狀態(tài)欄 開始
<div class="login-status-container auto-height">
<span class="welcome cell-8">
## 在 $ 之后 表達(dá)式之前使用 ! 表示 安靜模式 ( 靜默模式 )
<b>歡迎$!user.username來到愛問社區(qū)</b>
</span>
<span class="login-operation cell-4">
#if( $user )
<a href="$path/ask.html">提問</a>
<em>|</em>
<a href="$path/myQuestion.do">我的提問</a>
<em>|</em>
<a href="$path/logout.do">注銷</a>
#else
<a href="$path/login.html">登錄</a>
<em>|</em>
<a href="$path/regist.html">注冊</a>
#end
</span>
</div> ## 登錄狀態(tài)欄 結(jié)束
## 標(biāo)志區(qū)域
<div class="brand-container auto-height">
<div class="cell-2">
<a href="$path"></a>
</div>
<div class="slogan cell-10">
<div>
愛問社區(qū),這里可放logo
</div>
</div>
</div>
## 列表區(qū)域
<div class="topic-list-container clear">
<!-- 問題列表的標(biāo)題 -->
<div class="topic-list-header row clear">
<span class="topic-item-index cell-1">序號(hào)</span>
<span class="topic-item-title cell-5" style="text-align: left ;">標(biāo)題</span>
<span class="topic-item-time cell-3">提問時(shí)間</span>
<span class="topic-item-user cell-2">提問者</span>
<span class="topic-item-operation cell-1">
#if( $user )
解答問題
#end
</span>
</div>
## 問題列表開始
## 每循環(huán)一次從 $topics 集合中取出一個(gè) Topic 對象 放到 $topic 中
#foreach( $topic in $topics )
<div class="topic-item row clear odd">
<span class="topic-item-index cell-1">$topic.id</span>
<span class="topic-item-title cell-5" style="text-align: left ;">
<a href="$path/detail.do?id=$topic.id">$topic.title</a>
</span>
<span class="topic-item-time cell-3"> $topic.publishTime </span>
<span class="topic-item-user cell-2"> $topic.user.username</span>
<span class="topic-item-operation cell-1">
#if( $user )
<a href="$path/answer.do?id=$topic.id">解答</a>
#end
</span>
</div>
#end
## 問題列表結(jié)束
</div>## 列表區(qū)域結(jié)束
<div class="line"></div>
<div class="container link-container">
<a href="$path/ask.html" >發(fā)起新問題</a>
|
<a href="$path/index.html" >返回首頁</a>
</div>
<div class="container copyright-container">
© 2017 愛問社區(qū)版權(quán)所有
</div>
</body>
</html>
提問前臺(tái)界面代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>提問</title>
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/wen.css">
<link rel="stylesheet" href="$path/styles/btn.css">
<!-- 鏈接 simditor 的樣式庫 -->
<link rel="stylesheet" href="$path/simditor/styles/simditor.css" type="text/css">
<!-- 導(dǎo)入 simditor 的 JavaScript 庫 -->
<script type="text/javascript" src="$path/simditor/scripts/jquery.min.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/module.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/hotkeys.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/uploader.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/simditor.min.js"></script>
</head>
<body>
## 登錄狀態(tài)欄 開始
<div class="id="topnav" class="f_r">
<span class="welcome cell-8">
## 在 $ 之后 表達(dá)式之前使用 ! 表示 安靜模式 ( 靜默模式 )
<b>歡迎$!user.username來到愛問社區(qū)</b>
</span>
<span class="login-operation cell-4">
#if( $user )
<a href="$path/ask.html">提問</a>
<em>|</em>
<a href="$path/myQuestion.do">我的提問</a>
<em>|</em>
<a href="$path/logout.do">注銷</a>
#else
<a href="$path/login.html">登錄</a>
<em>|</em>
<a href="$path/regist.html">注冊</a>
#end
</span>
</div> ## 登錄狀態(tài)欄 結(jié)束
<div class="brand-container auto-height">
<div class="cell-2">
<a href="$path"></a>
</div>
<div class="slogan cell-10">
<div>
愛問社區(qū),這里可以logo
</div>
</div>
</div>
<div class="container message-container">
<!-- 顯示提示信息的地方 -->
#if( $askFail )
$askFail
$scope.remove( $session , 'askFail' )
#end
</div>
#if( $user )
<!-- 提問表單 提交給 ask.do 對應(yīng)的 Servlet 處理 -->
<form action="$path/ask.do" method="post" >
<!-- 提問區(qū)域 開始 -->
<div class="container topic-ask-container clear shadow-outside auto-height" >
<!-- 問題的標(biāo)題 和 提問按鈕 -->
<div class="container title-container">
<div class="cell-11">
<input type="text" name="title" placeholder="請輸入你要提問的問題的標(biāo)題" class="u-ipt">
</div>
<div class="cell-1">
<input type="submit" value="提問" class="u-btn u-btn-c4">
</div>
</div>
<div class="line"></div>
<!-- 問題的內(nèi)容 -->
<div>
<textarea name="content" id="contentEditor" ></textarea>
<script type="text/javascript" >
var editor = new Simditor( {
textarea : $('#contentEditor'),
placeholder : '請?jiān)谶@里輸入問題的內(nèi)容...',
toolbar : true
} );
</script>
</div>
<div class="line"></div>
<!-- 最底部的提問按鈕 -->
<div class="container title-container">
<div class="cell-11" style="height: 1px ;"></div>
<div class="cell-1">
<input type="submit" value="提問" class="u-btn u-btn-c4">
</div>
</div>
</div> <!-- 提問區(qū)域 結(jié)束 -->
</form>
#else
<div style="text-align:center ; min-height: 400px ; line-height: 400px ;">
登錄以后才能發(fā)起提問,請<a href="$path/login.html" >登錄</a>
</div>
#end
<div class="line"></div>
<div class="container link-container">
<a href="$path/list.do" >問題列表</a>
|
<a href="$path/index.html" >返回首頁</a>
</div>
<div class="container copyright-container">
© 2017 愛問社區(qū)版權(quán)所有
</div>
</body>
</html>
回答Servlet處理代碼:
@WebServlet("/answer.do")
public class AnswerServlet extends HttpServlet {
private static final long serialVersionUID = 8578962149437664830L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 從 請求中獲得請求參數(shù)的值
String id = request.getParameter("id");
if (StringHelper.notEmpty(id)) {
try {
int topicId = Integer.parseInt(id); // 將字符串按照 十進(jìn)制 解析問 int 類型數(shù)值
// 根據(jù)得到的 問題的 主鍵 查詢數(shù)據(jù)庫,得到 詳細(xì)信息
final String SQL = "SELECT id , title , content , publish_time , publish_ip , user_id FROM t_topic WHERE id = ? ";
ResultSet rs = JdbcHelper.query(SQL, topicId);
Topic t = null;
int userId = -1;
if (rs.next()) { // 當(dāng) 根據(jù) 問題的主鍵 獲取到 問題信息時(shí)
t = new Topic(); // 創(chuàng)建 Topic 對象
t.setId(rs.getInt(1)); // 將 結(jié)果集 中的 該行數(shù)據(jù) 封裝到 t 對象的 id 屬性中
t.setTitle(rs.getString(2));
t.setContent(rs.getString(3));
t.setPublishTime(rs.getTimestamp(4));
t.setPublishIp(rs.getString(5));
userId = rs.getInt(6);
}
JdbcHelper.release(rs); // 關(guān)閉結(jié)果集
// 獲得提問者
final String getUserSQL = "SELECT id , username , password FROM t_user WHERE id = ? ";
rs = JdbcHelper.query(getUserSQL, userId);
if (userId != -1 && rs.next()) {
User u = new User();
// 封裝數(shù)據(jù)
u.setId(rs.getInt(1));
u.setUsername(rs.getString(2));
u.setPassword(rs.getString(3));
// 將獲取到的用戶數(shù)據(jù)設(shè)置到 Topic 對象的 user 屬性中
t.setUser(u);
}
HttpSession session = request.getSession();
session.setAttribute("topic", t);
response.sendRedirect(request.getContextPath() + "/answer.html");
return; // 讓方法立即結(jié)束
} catch (NumberFormatException e) {
e.printStackTrace();
// response.sendRedirect( request.getContextPath() + "/list.do" );
} catch (SQLException e) {
e.printStackTrace();
// response.sendRedirect( request.getContextPath() + "/list.do" );
}
} else {
// response.sendRedirect( request.getContextPath() + "/list.do" );
}
response.sendRedirect(request.getContextPath() + "/list.do");
}
}
回答前臺(tái)代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>解答: $topic.title</title>
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/wen.css">
<!-- 鏈接 simditor 的樣式庫 -->
<link rel="stylesheet" href="$path/simditor/styles/simditor.css" type="text/css">
<!-- 導(dǎo)入 simditor 的 JavaScript 庫 -->
<script type="text/javascript" src="$path/simditor/scripts/jquery.min.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/module.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/hotkeys.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/uploader.js"></script>
<script type="text/javascript" src="$path/simditor/scripts/simditor.min.js"></script>
</head>
<body>
## 登錄狀態(tài)欄 開始
<div class="login-status-container auto-height">
<span class="welcome cell-8">
## 在 $ 之后 表達(dá)式之前使用 ! 表示 安靜模式 ( 靜默模式 )
<b>歡迎$!user.username來到愛問社區(qū)</b>
</span>
<span class="login-operation cell-4">
#if( $user )
<a href="$path/ask.html">提問</a>
<em>|</em>
<a href="">我的提問</a>
<em>|</em>
<a href="$path/logout.do">注銷</a>
#else
<a href="$path/login.html">登錄</a>
<em>|</em>
<a href="$path/regist.html">注冊</a>
#end
</span>
</div> ## 登錄狀態(tài)欄 結(jié)束
## 標(biāo)志區(qū)域
<div class="brand-container auto-height">
<div class="logo cell-2">
<a href="$path"></a>
</div>
<div class="slogan cell-10">
<div>
解答問題
</div>
</div>
</div>
<div>
<h3>$topic.title</h3>
<div class="line"></div>
<div>
$topic.content
</div>
<div>
提問時(shí)間: $topic.publishTime / 提問者: $topic.user.username
</div>
</div>
<!-- 解答的內(nèi)容 -->
<form action="$path/explain.do" method="post" >
<input type="hidden" name="id" value="$topic.id" >
<div>
<textarea name="content" id="contentEditor" ></textarea>
<script type="text/javascript" >
var editor = new Simditor( {
textarea : $('#contentEditor'),
placeholder : '請?jiān)谶@里輸入問題的內(nèi)容...',
toolbar : true
} );
</script>
</div>
<input type="submit" value="提交解答">
</form>
$scope.remove( $session , 'topic' );
<div class="line"></div>
<div class="container link-container">
<a href="$path/ask.html" >發(fā)起新問題</a>
|
<a href="$path/index.html" >返回首頁</a>
</div>
<div class="container copyright-container">
© 2017 愛問社區(qū)版權(quán)所有
</div>
</body>
</html>
以下是使用simditor的方法,需要引入simditor中的css和js樣式。simditor下載地址
<textarea name="content" id="contentEditor" ></textarea>
<script type="text/javascript" >
var editor = new Simditor( {
textarea : $('#contentEditor'),
placeholder : '請?jiān)谶@里輸入問題的內(nèi)容...',
toolbar : true
} );
</script>
解答問題Servlet處理,這里需要獲取提問者,提問問題以及該問題的已有答案,已有答案回答者。
@WebServlet("/detail.do")
public class DetailServlet extends HttpServlet {
private static final long serialVersionUID = -3202278077673657729L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 從 請求中獲得請求參數(shù)的值
String id = request.getParameter("id");
if (StringHelper.notEmpty(id)) {
try {
int topicId = Integer.parseInt(id); // 將字符串按照 十進(jìn)制 解析問 int 類型數(shù)值
// 根據(jù)得到的 問題的 主鍵 查詢數(shù)據(jù)庫,得到 詳細(xì)信息
final String SQL = "SELECT id , title , content , publish_time , publish_ip , user_id FROM t_topic WHERE id = ? ";
ResultSet rs = JdbcHelper.query(SQL, topicId);
Topic t = null;
/*int userId = -1;*/
if (rs.next()) { // 當(dāng) 根據(jù) 問題的主鍵 獲取到 問題信息時(shí)
t = new Topic(); // 創(chuàng)建 Topic 對象
t.setId(rs.getInt(1)); // 將 結(jié)果集 中的 該行數(shù)據(jù) 封裝到 t 對象的 id 屬性中
t.setTitle(rs.getString(2));
t.setContent(rs.getString(3));
t.setPublishTime(rs.getTimestamp(4));
t.setPublishIp(rs.getString(5));
User user = new User();
user.setId(rs.getInt(6));
t.setUser(user);
}
JdbcHelper.release(rs); // 關(guān)閉結(jié)果集
// 獲得提問者
final String getUserSQL = "SELECT id , username , password FROM t_user WHERE id = ? ";
rs = JdbcHelper.query(getUserSQL, t.getUser().getId());
if(rs.next())
{
User u = new User();
// 封裝數(shù)據(jù)
u.setId(rs.getInt(1));
u.setUsername(rs.getString(2));
u.setPassword(rs.getString(3));
// 將獲取到的用戶數(shù)據(jù)設(shè)置到 Topic 對象的 user 屬性中
t.setUser(u);
System.out.println("message username:" + rs.getString(2));
}
JdbcHelper.release(rs); // 關(guān)閉結(jié)果集
// 獲得當(dāng)前的問題的所有解答
String explainSQL = "SELECT id , content , explain_time , explain_ip , user_id from t_explain where topic_id = ? ";
rs = JdbcHelper.query(explainSQL, topicId);
@SuppressWarnings("unused")
int explainerId = -1;
List<Explain> explains = new ArrayList<>();
while (rs.next()) {
Explain e = new Explain();
e.setId(rs.getInt(1));
e.setContent(rs.getString(2));
e.setExplainTime(rs.getTimestamp(3));
e.setExplainIp(rs.getString(4));
User user=new User();
user.setId(rs.getInt(5));
e.setUser(user);
explains.add(e);
System.out.println("explain userID:" + rs.getInt(5));
}
// 獲得解答者
List<Explain>explainList = new ArrayList();
for(int i=0;i<explains.size();i++)
{
Explain explain1 = explains.get(i);
final String getExplainerSQL = "SELECT id , username , password FROM t_user WHERE id = ? ";
rs = JdbcHelper.query(getExplainerSQL, explain1.getUser().getId());
if (rs.next()) {
User u = new User();
// 封裝數(shù)據(jù)
u.setId(rs.getInt(1));
u.setUsername(rs.getString(2));
u.setPassword(rs.getString(3));
// 將獲取到的用戶數(shù)據(jù)設(shè)置到 Topic 對象的 user 屬性中
explain1.setUser(u);
explainList.add(explain1);
System.out.println("explain username:" + rs.getString(2));
}
JdbcHelper.release(rs); // 關(guān)閉結(jié)果集
/*t.setExplains(explains); // 將解答設(shè)置到 Topic 對象上
*/ }
t.setExplains(explainList);
/*** 為 所有的解答,獲取解答者的詳細(xì)信息 ***/
HttpSession session = request.getSession();
session.setAttribute("topic", t);
response.sendRedirect( request.getContextPath() + "/detail.html" );
return; // 讓方法立即結(jié)束
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} else {
}
response.sendRedirect(request.getContextPath() + "/list.do");
}
}
解答問題前臺(tái)顯示界面代碼;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>$topic.title</title>
<link rel="shortcut icon" href="$path/images/icon.png" type="image/png">
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/wen.css">
</head>
<body>
## 登錄狀態(tài)欄 開始
<div class="login-status-container auto-height">
<span class="welcome cell-8">
## 在 $ 之后 表達(dá)式之前使用 ! 表示 安靜模式 ( 靜默模式 )
<b>歡迎$!user.username來到問道</b>
</span>
<span class="login-operation cell-4">
#if( $user )
<a href="$path/ask.html">提問</a>
<em>|</em>
<a href="">我的提問</a>
<em>|</em>
<a href="$path/logout.do">注銷</a>
#else
<a href="$path/login.html">登錄</a>
<em>|</em>
<a href="$path/regist.html">注冊</a>
#end
</span>
</div> ## 登錄狀態(tài)欄 結(jié)束
## 標(biāo)志區(qū)域
<div class="brand-container auto-height">
<div class="logo cell-2">
<a href="$path"></a>
</div>
<div class="slogan cell-10">
<div>
</div>
</div>
</div>
<div>
<h3>$topic.title</h3>
<div class="line"></div>
<div>
$topic.content
</div>
<div>
提問時(shí)間: $topic.publishTime / 提問者: $topic.user.username
</div>
</div>
<div>
#foreach( $ex in $topic.explains)
<div> $ex.content </div>
<div class="line"></div>
#end
</div>
$scope.remove( $session , 'topic' );
<div class="line"></div>
<div class="container link-container">
<a href="$path/ask.html" >發(fā)起新問題</a>
|
<a href="$path/index.html" >返回首頁</a>
</div>
<div class="container copyright-container">
© 2017 愛問社區(qū)版權(quán)所有
</div>
</body>
</html>
我的解答Servlet處理代碼:
@WebServlet("/myAnswer.do")
public class MyAnswerServlet extends HttpServlet {
private static final long serialVersionUID = -3020889403557912216L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute( "user" ); // 在登錄時(shí)將 User 對象放入了 會(huì)話 中
Explain ex=null;
final List<Explain> exp = new ArrayList<>();
if( user != null ) {
int myid=user.getId();
final String SQL = "SELECT id ,content ,explain_time , explain_ip , user_id ,topic_id FROM t_explain WHERE user_id = ? ";
ResultSet rs = JdbcHelper.query(SQL, myid);
//Topic t=null;
//final List<Explain> explains = new ArrayList<>();
@SuppressWarnings("unused")
int topicId=-1;
try {
while( rs.next() )
{
ex=new Explain();
ex.setId(rs.getInt(1));
ex.setContent(rs.getString(2));
ex.setExplainTime(rs.getTimestamp( 3 ));
ex.setExplainIp(rs.getString(4));
ex.setUser(user);
Topic to=new Topic();
to.setId(rs.getInt(6));
ex.setTopic(to);
topicId=rs.getInt(6);
exp.add(ex);
}
JdbcHelper.release(rs); // 關(guān)閉結(jié)果集
for(int i = 0 , len = exp.size() ; i < len ; i++)
{
Explain explain=exp.get(i);
Topic tid=explain.getTopic();
final String tSQL = "SELECT id , title , content , publish_time , publish_ip , user_id FROM t_topic WHERE id = ? ";
ResultSet trs = JdbcHelper.query(tSQL, tid.getId());
while(trs.next())
{
Topic t=new Topic();
t.setId(1);
t.setTitle(trs.getString(2));
t.setContent(trs.getString(3));
t.setPublishTime(trs.getTimestamp(4));
t.setPublishIp(trs.getString(5));
ex.setTopic(t);
// explains.add(ex);
System.out.println( "我的tid: " + tid.getId());
}
JdbcHelper.release(trs); // 關(guān)閉結(jié)果集
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
session.setAttribute("explains", exp);
System.out.println( "我的解答列表: " + exp );
System.out.println( "我的id: " + myid);
response.sendRedirect( request.getContextPath() + "/myAnswer.html");
}
}
}
我的解答前臺(tái)展示頁面代碼:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>解答</title> <link rel="stylesheet" href="$path/styles/top.css"> </head> <body> <div style="margin-left:320px;"> <nav id="topnav" class="f_r"> <ul> <a href="$path/index.html"">首頁</a> <a href="$path/myQuestion.do" >我的提問</a> <a href="$path/ask.html" >提問</a> <a href="$path/logout.do">注銷</a> </ul> </nav> </div> #if( $user ) $user.username的所有回答: #end #foreach( $ex in $explains) <div class="blogs"> <ul> <p>$ex.content</p> <div class="content_time"> <p> 解答時(shí)間:<span class="dtime f_l"> $ex.explainTime</span></p> </div> <div class="line"></div> </ul> </div> #end </body> </html>
我的提問Servlet處理:
@WebServlet("/myQuestion.do")
public class MyQuestionServlet extends HttpServlet {
private static final long serialVersionUID = -4110483126223561394L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute( "user" ); // 在登錄時(shí)將 User 對象放入了 會(huì)話 中
if( user != null ) {
int myid=user.getId();
final String SQL = "SELECT id , title , content, publish_time , publish_ip FROM t_topic WHERE user_id = ? ";
ResultSet rs = JdbcHelper.query(SQL, myid);
final List<Topic> qtopics = new ArrayList<>();
try {
while( rs.next() ){
Topic t=new Topic();
t.setId(rs.getInt(1));
t.setTitle(rs.getString(2));
t.setContent(rs.getString(3));
t.setPublishTime(rs.getTimestamp(4));
t.setPublishIp(rs.getString(5));
qtopics.add(t);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
session.setAttribute("qtopics", qtopics);
System.out.println( "我的提問列表: " + qtopics );
System.out.println( "我的id: " + myid);
response.sendRedirect( request.getContextPath() + "/myQuestion.html");
}
}
}
我的提問展示代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>$user.username的提問 </title>
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/wen.css">
<link rel="stylesheet" href="$path/styles/top.css">
</head>
<body>
<div style="margin-left:320px;">
<ul>
#if($user)
<nav id="topnav" class="f_r">
<ul>
<a href="$path/index.html">首頁</a>
<a href="$path/myAnswer.do" >我的解答</a>
<a href="$path/ask.html">提問</a>
<a href="$path/logout.do" >注銷</a>
</ul>
</nav>
#else
<li class="presentation"><a href="$path/login.html" id="link" title="提問">登錄</a></li>
<li class="presentation"><a href="$path/regist.do" id="tools" title="exit">注冊</a></li>
#end
</ul>
</div>
#if( $user )
$user.username的所有提問:
#end
#foreach( $qto in $qtopics)
<div class="blogs">
<ul>
<p>$qto.content</p>
<p class="autor"><span class="lm f_l"><a>提問者:$user.username</a></span> <span class="dtime f_l">$qto.publishTime</span></p>
</ul>
</div>
#end
</body>
</html>
驗(yàn)證碼處理的Servlet代碼:
@WebServlet(urlPatterns= { "/verify/login.do" , "/verify/regist.do" } )
public class VerifyCodeServlet extends HttpServlet {
private static final long serialVersionUID = 3398560501558431737L;
@Override
protected void service( HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {
// 獲得 當(dāng)前請求 對應(yīng)的 會(huì)話對象
HttpSession session = request.getSession();
// 從請求中獲得 URI ( 統(tǒng)一資源標(biāo)識(shí)符 )
String uri = request.getRequestURI();
System.out.println( "hello : " + uri );
final int width = 180 ; // 圖片寬度
final int height = 40 ; // 圖片高度
final String imgType = "jpeg" ; // 指定圖片格式 (不是指MIME類型)
final OutputStream output = response.getOutputStream(); // 獲得可以向客戶端返回圖片的輸出流 (字節(jié)流)
// 創(chuàng)建驗(yàn)證碼圖片并返回圖片上的字符串
String code = GraphicHelper.create( width, height, imgType, output );
System.out.println( "驗(yàn)證碼內(nèi)容: " + code );
// 建立 uri 和 相應(yīng)的 驗(yàn)證碼 的關(guān)聯(lián) ( 存儲(chǔ)到當(dāng)前會(huì)話對象的屬性中 )
session.setAttribute( uri , code );
System.out.println( session.getAttribute( uri ) );
}
}
注冊前臺(tái)界面,有驗(yàn)證碼驗(yàn)證功能:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>注冊愛問社區(qū)</title>
<link rel="stylesheet" href="$path/styles/general.css">
<link rel="stylesheet" href="$path/styles/cell.css">
<link rel="stylesheet" href="$path/styles/form.css">
<link rel="stylesheet" href="$path/awesome/css/font-awesome.min.css">
<script type="text/javascript" src="$path/js/wen.js"></script>
<style type="text/css" >
.logo-container {
margin-top: 50px ;
}
.logo-container img {
width: 100px ;
}
.message-container {
height: 80px ;
}
.link-container {
height: 40px ;
line-height: 40px ;
}
.link-container a {
text-decoration: none ;
}
</style>
</head>
<body>
<div class="container title-container" style="color:blue; margin-top:60px;">加入愛問社區(qū),為您答疑解惑</div>
<div class="container form-container">
<form action="$path/regist.do" method="post">
<div class="form"> <!-- 注冊表單開始 -->
<div class="form-row">
<span class="cell-1">
<i class="fa fa-user"></i>
</span>
<span class="cell-11" style="text-align: left;">
<input type="text" name="username" placeholder="請輸入用戶名">
</span>
</div>
<div class="form-row">
<span class="cell-1">
<i class="fa fa-key"></i>
</span>
<span class="cell-11" style="text-align: left;">
<input type="password" name="password" placeholder="請輸入密碼">
</span>
</div>
<div class="form-row">
<span class="cell-1">
<i class="fa fa-keyboard-o"></i>
</span>
<span class="cell-11" style="text-align: left;">
<input type="password" name="confirm" placeholder="請確認(rèn)密碼">
</span>
</div>
<div class="form-row">
<span class="cell-7">
<input type="text" name="verifyCode" placeholder="請輸入驗(yàn)證碼">
</span>
<span class="cell-5" style="text-align: center;">
<img src="$path/verify/regist.do" onclick="myRefersh(this)">
</span>
</div>
<div class="form-row" style="border: none;">
<span class="cell-6" style="text-align: left">
<input type="reset" value="重置">
</span>
<span class="cell-6" style="text-align:right;">
<input type="submit" value="注冊">
</span>
</div>
</div> <!-- 注冊表單結(jié)束 -->
</form>
</div>
<div class="container message-container">
<!-- 顯示提示信息的地方 -->
#if( $registFail )
$registFail
$scope.remove( $session , 'registFail' )
#end
</div>
<div class="container link-container">
<a href="$path/login.html" > 已注冊愛問帳號(hào),點(diǎn)擊這里登錄</a>
|
<a href="$path/index.html" >返回首頁</a>
</div>
<div class="container copyright-container">
© 2017 愛問社區(qū)版權(quán)所有
</div>
</body>
</html>
Servlet處理注冊,實(shí)現(xiàn)驗(yàn)證碼驗(yàn)證:
@WebServlet("/regist.do")
public class RegistServlet extends HttpServlet {
private static final long serialVersionUID = 7493633832455111617L;
@Override
protected void service( HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {
// 獲得來自 頁面 表單上的數(shù)據(jù)
String verifyCode = request.getParameter( "verifyCode" ) ; // 獲得由用戶輸入的那個(gè)驗(yàn)證碼
String username = request.getParameter( "username" ) ;
String password = request.getParameter( "password" ) ;
String confirm = request.getParameter( "confirm" ) ;
System.out.println( "username : " + username );
System.out.println( "password : " + password );
System.out.println( "confirm : " + confirm );
System.out.println( "verifyCode : " + verifyCode );
HttpSession session = request.getSession();
// 獲得 在 會(huì)話 中存儲(chǔ)的那個(gè) 為登錄進(jìn)行驗(yàn)證的 驗(yàn)證碼
final String code = (String)session.getAttribute( "/wendao/verify/regist.do" );
System.out.println( "session code : " + code );
// 比較驗(yàn)證碼
if( StringHelper.equals( verifyCode , code ) ){
// 要保證 用戶名 不為空 、密碼不能為空 、兩次輸入的密碼必須一致
if( StringHelper.notEmpty( username )
&& StringHelper.notEmpty( password )
&& StringHelper.equals( password , confirm) ) {
// 可以保存了
String SQL = "INSERT INTO t_user ( username , password ) VALUES ( ? , ? ) " ;
int n = JdbcHelper.insert( SQL , false , username , StringHelper.MD5(password));
if( n > 0 ) { // 如果 insert 返回 大于 0 的數(shù)字 , 則表示 插入成功
// 保存成功以后,應(yīng)該去一個(gè)新的頁面 ( 比如去 登錄頁面 )
response.sendRedirect( request.getContextPath() + "/login.html" );
} else {
// 回到注冊頁面去
session.setAttribute( "registFail" , "注冊失敗,可能是用戶名被占用了" );
response.sendRedirect( request.getContextPath() + "/regist.html" );
}
} else {
// 回到注冊頁面去
session.setAttribute( "registFail" , "用戶名或密碼為空,或者密碼不一致" );
response.sendRedirect( request.getContextPath() + "/regist.html" );
}
} else {
// 如果驗(yàn)證碼不一致,設(shè)置提示信息后回到注冊頁面去
session.setAttribute( "registFail" , "驗(yàn)證碼輸入錯(cuò)誤,請重新輸入" );
response.sendRedirect( request.getContextPath() + "/regist.html" );
}
}
}
登錄Servlet處理代碼:
@WebServlet("/login.do")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 18854422651747352L;
@Override
protected void service( HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {
// 獲得來自 頁面 表單上的數(shù)據(jù)
String username = request.getParameter( "username" ) ;
String password = StringHelper.MD5(request.getParameter( "password" )) ;
System.out.println( "username : " + username );
System.out.println( "password : " + password );
HttpSession session = request.getSession();
// 登錄 : 根據(jù) 用戶名 和 密碼 從數(shù)據(jù)庫中查詢數(shù)據(jù),如果都正確,就將這些數(shù)據(jù)放入到會(huì)話中,最后進(jìn)入到指定頁面( list.html )
String SQL = "SELECT id , username , password FROM t_user WHERE username = ? and password = ? " ;
ResultSet rs = JdbcHelper.query( SQL, username , password ) ;
try{
// 如果查詢到數(shù)據(jù),就包裝到一個(gè)對象中
if( rs.next() ) {
User user = new User(); // 創(chuàng)建對象
// 封裝數(shù)據(jù)
user.setId( rs.getInt( 1 ) );
user.setUsername( rs.getString( 2 ));
user.setPassword( rs.getString( 3 ) ) ;
//System.out.println("測試"+MD5.convertMD5(MD5.convertMD5(password)));
/** 將 User 對象 放入到 會(huì)話中 **/
session.setAttribute( "user" , user );
// 重定向到 list.do ( list.do 會(huì)先查詢數(shù)據(jù)后 再 重定向到 list.html )
response.sendRedirect( request.getContextPath() + "/list.do" );
} else {
// 如果 用戶名 或 密碼 錯(cuò)誤,重新返回到 登錄頁面
session.setAttribute( "loginFail" , "用戶名或密碼錯(cuò)誤" );
response.sendRedirect( request.getContextPath() + "/login.html" );
}
} catch ( SQLException e ){
e.printStackTrace();
}
}
}
登錄前臺(tái)展示界面代碼;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登錄</title>
<link rel="stylesheet" href="styles/general.css">
<link rel="stylesheet" href="styles/cell.css">
<link rel="stylesheet" href="styles/form.css">
<link rel="stylesheet" href="awesome/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="css/login.css">
<script type="text/javascript" src="js/wen.js"></script>
</head>
<body>
<div class="logina-logo" style="height: 55px">
<div id="venusLogo"><p><span>愛問社區(qū)</span></p></div>
</div>
<div class="logina-main main clearfix">
<div class="tab-con">
<form action="$path/login.do" method="post">
<div id='login-error' class="error-tip"></div>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<th>賬戶</th>
<td width="245">
<input type="text" name="username" id="username" placeholder="昵稱" />
<td>
</td>
</tr>
<tr>
<th>密碼</th>
<td width="245">
<input type="password" name="password" id="password" placeholder="密碼" />
</td>
<td>
</td>
</tr>
<tr>
<th></th>
<td width="245"><input class="confirm" type="submit" value="登 錄"></td>
<td></td>
</tr>
</tbody>
</table>
</form>
</div>
<div class="reg">
<p>還沒有賬號(hào)?<br>趕快免費(fèi)注冊一個(gè)吧!</p>
<a class="reg-btn" href="regist.html">立即免費(fèi)注冊</a>
</div>
</div>
<div id="footer">
<div class="copyright">Copyright © 愛問社區(qū) 版權(quán)所有</div>
</div>
</body>
</html>
好啦,基本的代碼就展示完了,還有比較通用的POJO類和jdbc連接數(shù)據(jù)庫的類就不做展示了,貼上數(shù)據(jù)庫SQL代碼,需要的可以根據(jù)字段來寫
DROP TABLE IF EXISTS `t_explain`; CREATE TABLE `t_explain` ( `id` int(11) NOT NULL AUTO_INCREMENT, `content` text, `explain_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, `explain_ip` varchar(50) DEFAULT NULL, `user_id` int(8) DEFAULT NULL, `topic_id` int(8) DEFAULT NULL, PRIMARY KEY (`id`), KEY `ex_id` (`user_id`), KEY `t_id` (`topic_id`), CONSTRAINT `ex_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`), CONSTRAINT `t_id` FOREIGN KEY (`topic_id`) REFERENCES `t_topic` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for t_topic -- ---------------------------- DROP TABLE IF EXISTS `t_topic`; CREATE TABLE `t_topic` ( `id` int(10) NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `content` text, `publish_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `publish_ip` varchar(100) DEFAULT NULL, `user_id` int(10) DEFAULT NULL, PRIMARY KEY (`id`), KEY `cid` (`user_id`), CONSTRAINT `cid` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 基于jsp+servlet實(shí)現(xiàn)的簡單博客系統(tǒng)實(shí)例(附源碼)
- 相冊管理系統(tǒng)(Java表單+xml數(shù)據(jù)庫存儲(chǔ))
- 一個(gè)簡陋的java圖書管理系統(tǒng)
- Java+Mysql學(xué)生管理系統(tǒng)源碼
- 簡單實(shí)現(xiàn)Java版學(xué)生管理系統(tǒng)
- 圖書管理系統(tǒng)java版
- java編寫簡單的ATM存取系統(tǒng)
- 使用Java編寫一個(gè)簡單的Web的監(jiān)控系統(tǒng)
- Java 模擬銀行自助終端系統(tǒng)
- java開發(fā)就業(yè)信息管理系統(tǒng)
相關(guān)文章
Spring Boot實(shí)現(xiàn)功能的統(tǒng)一詳解
這篇文章主要介紹了Spring Boot統(tǒng)一功能的處理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
spring學(xué)習(xí)之創(chuàng)建項(xiàng)目 Hello Spring實(shí)例代碼
這篇文章主要介紹了spring學(xué)習(xí)之創(chuàng)建項(xiàng)目 Hello Spring實(shí)例代碼,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
手動(dòng)編譯并運(yùn)行Java項(xiàng)目實(shí)現(xiàn)過程解析
這篇文章主要介紹了手動(dòng)編譯并運(yùn)行Java項(xiàng)目實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
Java多線程定時(shí)器Timer原理及實(shí)現(xiàn)
這篇文章主要介紹了Java多線程定時(shí)器Timer原理及實(shí)現(xiàn),涉及Timer的schedule的使用,定時(shí)器Timer的schedule等相關(guān)內(nèi)容以及代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11

