前言:这个小项目是我刚学习JSP时,参考“JSP程序设计”这本书写的。这里之所以说参考这本书而不是照着这本书写,主要是因为我自己完成的时候删掉了不少繁琐的写法(比如:文件上传);同时对书中容易产生SQL注入漏洞,XSS跨站脚本漏洞等地方的写法进行了修改过滤;登录页面加上了随机验证码。除此之外,还添加了文件管理功能

PS:整个项目没有特别的难点,可以分为一个个功能点实现,大神轻喷,个人认为对初学Java Web的童鞋还是有参考意义的

注:整个项目的完整源代码和sql文件我会在文末给出下载链接


一 项目开发环境以及主要视图

1 开发环境:

本项目采用了最基本的JSP MVC模式(javabean+jsp+servlet)开发,数据库使用了MySQL,JDBC连接采用了JNDI连接池。除此之外,代码开发用了JDK1.8+tomcat8+eclipse for javaee,编码统一使用了UTF-8

2 主要视图:

(1)首页:

wKioL1ZbEMiQtcxuAAKbklFtEB8077.png

(2)注册

wKioL1ZbEOrQ0M5RAADceMsUAoI078.png

(3)登录

wKiom1ZbELbBUCErAAJ3SLICeNk399.png

(4)个人信息

wKiom1ZbEN3TU1GnAAKE7FB9diY784.png

(5)会员详细信息

wKioL1ZbEV2CNnsRAAJzkR4_OOs852.png

(6)文章列表

wKioL1ZbEXzwpR7tAAI0nmVvq-k199.png

(7)文章详情

wKioL1ZbEZeDsjeeAAGarjkKM74088.png

注:整个项目的主要视图差不多就是这些了,其他的我就不截图了


二 开发流程

1 简介:

用基本的JSP MVC模式开发网站,我总结的思路是这样的:(1)首先封装dao层的数据库操作(如:增删改查);(2)前台视图页面xx.jsp;(3)在web.xml里配置servlet;(4)最后是在action层(servlet)里调用dao层里的数据库操作完成相应的功能(比如:注册就是讲用户提交的数据写入数据库中);(4)根据操作是否成功给用户返回相应的显示页面yy.jsp

(PS:在这里我省略了业务逻辑层biz,结构太复杂对新手来说反而不容易入门。另:自我检讨下,当时写这个代码时候对分层思想不是很熟悉,所以大部分的dao层的具体操作都给写到servlet中去了

2 以注册这个功能点举例,其他功能点可以仿照这个步骤完成

(1)dao层的数据库连接DbConn.java。返回一个Connection(这里我做的不好,只有一个数据库连接功能,其他的增删改查都写到action层里去了)

package com.zifangsky.OnlineFriend.util;

import java.sql.Connection;
import java.sql.DriverManager;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class DbConn {	
	/**
	 * 通过JNDI连接池的方式
	 * */
	public static Connection getConnection(){
		try {			
			InitialContext context = new InitialContext();
			DataSource dSource = (DataSource) context.lookup("java:comp/env/jdbc/onlinefriend");
			Connection conn = dSource.getConnection();
			
			return conn;						
		} catch (Exception e) {			
			e.printStackTrace();
		}		
		return null;
	}
	
	/**
	 * 最基本的方式
	 * */
//	private static String driver = "com.mysql.jdbc.Driver";
//	private static String url = "jdbc:mysql://127.0.0.1:3306/onlinefriend?useUnicode=true&characterEncoding=utf-8";
//	private static String user = "root";
//	private static String passwd = "root";
	
//	public static Connection getConnection(){
//		try {
//			//加载驱动
//			Class.forName(driver);			
//			//连接数据库
//			Connection conn = DriverManager.getConnection(url,user,passwd);
//		
//			return conn;						
//		} catch (Exception e) {			
//			e.printStackTrace();
//		}		
//		return null;
//	}
	
}

注:如果对JNDI不熟悉,可以使用注释中的那种连接方式


(2)视图页面register.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<base href="<%=basePath%>">
<%@ include file="head.txt"%>
</head>
<body>
	<font size=3><br>
		<center>
			<form action="helpRegister" name="" method="post">
				<table>
					<caption>带<font color=red> * </font>号项为必填项</caption>
					<tr><td align=left>会员名称:</td><td><input type=text name="id"><font color=red> *</font></td></tr>
					<tr><td align=left>设置密码:</td><td><input type=password name="password"><font color=red> *</font></td></tr>
					<tr><td align=left>电子邮箱:</td><td><input type=text name="email"></td></tr>
					<tr><td align=left>联系电话:</td><td><input type=text name="phone"></td></tr>
				</table>	
				<table>
					<tr><td align=left>输入您的简历和交友标准:</td></tr>
					<tr>
						<td align=left><TextArea name="message" rows="6" cols="30"></TextArea></td>
					</tr>
					<tr><td align=center><input type=submit name="submit" value="注册"></td></tr>
				</table>
			</form>
		</center>
	</font>

</body>
</html>

注:1)页头加上了

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<base href="<%=basePath%>">

是为了使项目中的所有链接的路径都是相对于项目路径的,因此即使项目的部署路径改变了也不用重新修改以前的链接路径,现在一般都会把这两句话加上


2)注册页面建议加上一个随机生成的token参数,然后分两处保存,一处是在session中,一处是在表单中,提交表单后通过比较两个值是否一样来防止不法份子用软件来批量提交注册(PS:我这里忘记写了

表单之前添加:

<%
	String tokenValue = String.valueOf(System.currentTimeMillis());
%>

表单中添加:

<div>
                	<input type="hidden" name="token" value="<%=tokenValue %>">
					<%
						session.setAttribute("token", tokenValue);
					%>
                </div>

3)servlet中这样验证:

public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		HttpSession session = request.getSession(true);
		
		String token = StringUtil.xssEncode(request.getParameter("token").trim());
		Object token_session = session.getAttribute("token");
		if(token_session != null && token_session.equals(token)){
			session.removeAttribute("token");  //重要
			continueDoPost(request,response);
		}
		else{
			response.sendRedirect("index.jsp");
			return;
		}		
	}

	private void continueDoPost(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException{
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		HttpSession session = request.getSession(true);
		//后面的省略
	}

(3)web.xml添加一个节点:

<!-- 注册 -->
  <servlet>
    <servlet-name>register</servlet-name>
    <servlet-class>com.zifangsky.OnlineFriend.servlet.member.HandleRegister</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>register</servlet-name>
    <url-pattern>/helpRegister</url-pattern>
  </servlet-mapping>

(4)servlet页面HandleRegister.java,调用了对应的javabean来保存参数值

package com.zifangsky.OnlineFriend.servlet.member;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.zifangsky.OnlineFriend.model.member.Register;
import com.zifangsky.OnlineFriend.util.DbConn;
import com.zifangsky.OnlineFriend.util.StringUtil;

public class HandleRegister extends HttpServlet{
	private String backNews = "",pic = "public.jpg";  //pic为图片信息
	
	public void init(ServletConfig config) throws ServletException{
		super.init(config);
	}
	
	public void doPost(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
		Register registerBean = new Register();
		request.setAttribute("register", registerBean);
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		
		//获取注册信息
		String id = StringUtil.xssEncode(request.getParameter("id").trim());
		String password = StringUtil.xssEncode(request.getParameter("password").trim());
		String email = StringUtil.xssEncode(request.getParameter("email").trim());
		String phone = StringUtil.xssEncode(request.getParameter("phone").trim());
		String message = StringUtil.xssEncode(request.getParameter("message"));
		
		boolean isSuccess = false;  //判断注册信息是否符合规定
		if(StringUtil.isNotEmpty(id) &&StringUtil.isNotEmpty(password)){
			isSuccess = true;
			//判断id是否符合标准
			for(int i=0;i<id.length();i++){
				char c = id.charAt(i);
				if(!((c>='a'&&c<='z') || (c>='A'&&c<='Z') || (c>='0'&&c<='9'))){
					isSuccess = false;
					break;
				}
			}
		}
				
		//向 mysql 中注册用户			
		try {	
			if(isSuccess){
				Connection conn = DbConn.getConnection();
				PreparedStatement preparedStatement = conn.prepareStatement("insert into member(id,password,email,phone,message,pic) values(?,?,?,?,?,?)");
				preparedStatement.setString(1, id);
				preparedStatement.setString(2, password);
				preparedStatement.setString(3, email);
				preparedStatement.setString(4, phone);
				preparedStatement.setString(5, message);
				preparedStatement.setString(6, pic);
				
				//执行成功返回行数大于0
				int num = preparedStatement.executeUpdate();
				if(num != 0){
					backNews = "注册成功";
					registerBean.setBackNews(backNews);
					registerBean.setId(id);
					registerBean.setPassword(password);
					registerBean.setEmail(email);
					registerBean.setPhone(phone);
					registerBean.setMessage(message);
					registerBean.setRegisterSuccess(true);
				}
				preparedStatement.close();
				conn.close();
			}
			else{
				backNews = "信息填写不完整或者名字中有非法字符";
				registerBean.setBackNews(backNews);
			}			
		} catch (SQLException e) {
			backNews = "该ID已被使用,请更换ID";
			registerBean.setBackNews(backNews);
		}
				
		RequestDispatcher dispatcher = request.getRequestDispatcher("showRegisterMess.jsp");
		dispatcher.forward(request, response);	
	}
	
	public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
		doPost(request, response);
	}
}

(5)注册成功的显示视图showRegisterMess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
    <%@ page import="com.zifangsky.OnlineFriend.model.member.Register"%>
<jsp:useBean id="register" type="com.zifangsky.OnlineFriend.model.member.Register" scope="request"/>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<base href="<%=basePath%>">
<%@ include file="head.txt"%>
</head>
<body>	
	<center>
		<font size=4 color=blue>
			<br><jsp:getProperty name="register" property="backNews"/>
		</font>
		<% if(register.isRegisterSuccess()){ %>
			<font size=3>
				<table>
					<tr><td align=left>注册的会员名称:</td><td><jsp:getProperty name="register" property="id"/></td></tr>
					<tr><td align=left>注册的电子邮箱:</td><td><jsp:getProperty name="register" property="email"/></td></tr>
					<tr><td align=left>注册的联系电话:</td><td><jsp:getProperty name="register" property="phone"/></td></tr>
				</table>	
				<table>
					<tr><td align=left>您的简历和交友标准:</td></tr>
					<tr>
						<td align=left><TextArea name="message" rows="6" cols="30"><jsp:getProperty name="register" property="message"/></TextArea></td>
					</tr>
				</table>
			</font>
		<%}
			else{%>
			<br><a href="register.jsp">点击这里,重新注册</a>
			<%} %>
	</center>
	

</body>
</html>

OK,一个完整的功能点就这样做完了,其他功能点可以自行参考这个步骤完成


三 分享几个以前因为这个小项目而写的几篇博文

JavaWeb中连接数据库的一般方式与通过JNDI连接池的方式

在JSP中动态生成随机验证码,登录时后台校验验证码,以及如何避免同一个验证码被重复提交爆破密码

在Java中利用Apache Commons Codec API实现常见的加密解密算法,如:md5,sha256

JSP中 request.getRealPath(“/xx/yy”) 方法提示已经过时的替代方法

附:源代码和sql文件下载链接:http://down.51cto.com/data/2123238

(PS:如果没有下载豆的话,可以看我个人博客上的这篇文章,里面有百度云盘的链接。传送门:Java Web入门项目之“网络交友”的设计与实现