此项目主要实现的功能有:
jsp连接数据库、MD5加密、验证码验证、Ajax、文件的上传与下载、session登录验证等。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
WormJam-登录
WormJam
秀出你的源代码
登录的表单里先不看验证码,为了限制账号及密码 的格式为6至16位的数字或字母,用input里的onInput事件,当账号或密码框中的值发生改变时即调用accountChange()或passwordChange()函数进行输入格式的验证。accountChange()中的正则表达式/[a-zA-Z0-9]{6,16}/;表示6至16位的字母或数字,passwordChange()中的/1+$/表示键盘上能够输入的符号。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%@ page import="java.awt.*" import="java.awt.image.BufferedImage" import="javax.imageio.ImageIO" %>
<%
response.setHeader("Cache-Control", "no-cache");
//在内存中创建图像
int width = 60,height = 20;
BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//获取画笔
Graphics g = image.getGraphics();
//设置背景色
g.setColor(new Color(200,200,200));
g.fillRect(0,0,width,height);
//随机产生验证码
Random rnd = new Random();
int randNum = rnd.nextInt(8999) + 1000;
String randStr = String.valueOf(randNum);
//将验证码存入session
session.setAttribute("randStr",randStr);
//将验证码显示在图像中
g.setColor(Color.black);
g.setFont(new Font("",Font.PLAIN,20));
g.drawString(randStr,10,17);
//随机产生100个随机点
for(int i=0;i<100;i++){
int x = rnd.nextInt(width);
int y = rnd.nextInt(height);
g.drawOval(x,y,1,1);
}
//输出图像到页面
ImageIO.write(image,"JPEG", response.getOutputStream());
out.clear();
out = pageContext.pushBody();
%>
这段代码生成一个验证码并放在图片中显示,然后login.jsp的登录表单中用img标签把这个验证码图片加载进来。
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ValidateServlet extends HttpServlet { //对验证码验证
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到提交的验证码
String code = request.getParameter("code");
//获取session中的验证码
HttpSession session = request.getSession();
String randStr = (String)session.getAttribute("randStr");
//response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
if(!code.equals(randStr)){
out.println("");
}
else{
out.print("√");
}
}
}
当输入的验证码正确时输出"√",错误时输出空格(无显示),顺便说一句,login.jsp里的validateSubmit()可以看到,我的登录表单是通过判定输出的文本来提交的,即如果账号密码和验证码后面的文本输出不全是"√"的话就无法提交表单。
现在的问题是,在servlet中输出的话,浏览器会新打开一个页面来显示验证码验证的结果,所以要用到AJAX把输出显示在登录页验证码图片的后面,login.jsp里的validate()就使用了AJAX,使验证码验证的结果显示在id为codeText的span标签里,并传一个名为code值为你输入的验证码的参数给ValidateServlet。验证正确时就可以提交给LoginServlet进行密码的验证了。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
WormJam-注册
WormJam
秀出你的源代码
表单方面包括格式验证、AJAX都和登录页面同理,提交给RegisterServlet注册,现在就要开始连接数据库操作了。JSP连接数据库的一些配置我就不赘述了。
create table ACCOUNTS(
ACNAME varchar(16) not null,
PASSWD varchar(16) not null
);
为了方便就写了这两列,账号名和密码,16位不为空。然后数据库我是采用DAO设计模式。
package VO;
public class Account {
private String account; //定义账户
private String password; //定义密码
public String getAccount(){
return account;
}
public void setAccount(String account){
this.account = account;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password = password;
}
}
分别定义了get和set方法。
package dbc;
import java.sql.*;
public class DatabaseConnection {
private static final String DBDRIVER = "org.gjt.mm.mysql.Driver" ;
private static final String DBURL = "jdbc:mysql://localhost:3306/wormjam" ;
private static final String DBUSER = "root" ;
private static final String DBPASSWORD = "你的密码" ;
private Connection conn ;
public DatabaseConnection() throws Exception { //在构造方法中进行数据库连接
Class.forName(DBDRIVER) ; //加载驱动程序
this.conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD) ;
}
public Connection getConnection(){ //取得数据库连接
return this.conn ;
}
public void close() throws Exception { //关闭数据库
if(this.conn != null){
try{
this.conn.close() ;
}catch(Exception e){
throw e ;
}
}
}
}
package DAO ;
import java.util.* ;
import VO.Account;
public interface IAccountDAO { //定义DAO操作
public boolean doCreate(Account account) throws Exception ;
public String findByAccount(String acname) throws Exception ;
}
定义了两个操作:创建和寻找。创建用来注册用户,而寻找用来比对密码是否正确。
package DAO ;
import java.util.* ;
import java.sql.* ;
import DAO.IAccountDAO;
import VO.Account;
public class AccountDAOImpl implements IAccountDAO {
private Connection conn = null ; //数据库连接对象
private PreparedStatement pstmt = null ; //数据库操作对象
public AccountDAOImpl(Connection conn){ //通过构造方法取得数据库连接
this.conn = conn ;
}
public boolean doCreate(Account account) throws Exception{ //添加账户
boolean flag = false ; //定义标志位
String sql = "INSERT INTO ACCOUNTS(ACNAME,PASSWD) VALUES (?,?)" ;
this.pstmt = this.conn.prepareStatement(sql) ; //实例化PrepareStatement对象
this.pstmt.setString(1,account.getAccount()) ;
this.pstmt.setString(2,account.getPassword()) ;
if(this.pstmt.executeUpdate() > 0){ //如果有更新操作
flag = true ;
}
this.pstmt.close() ;
return flag ;
}
public String findByAccount(String acname) throws Exception{//按账号查找密码
String password = null;
String sql = "SELECT PASSWD FROM ACCOUNTS WHERE ACNAME=?" ;
this.pstmt = this.conn.prepareStatement(sql) ;
this.pstmt.setString(1,acname);
ResultSet rs = this.pstmt.executeQuery() ;
if(rs.next()){
password = rs.getString("PASSWD");
}
this.pstmt.close() ;
return password ;
}
}
package DAO ;
import java.util.* ;
import java.sql.* ;
import DAO.AccountDAOImpl;
import DAO.IAccountDAO;
import dbc.DatabaseConnection;
import VO.Account;
public class AccountDAOProxy implements IAccountDAO {
private DatabaseConnection dbc = null ;
private IAccountDAO dao = null ;
public AccountDAOProxy() throws Exception { //在构造方法中实例化连接,同时实例化dao对象
this.dbc = new DatabaseConnection() ;
this.dao = new AccountDAOImpl(this.dbc.getConnection()) ;
}
public boolean doCreate(Account account) throws Exception{
boolean flag = false ;
try{
if(this.dao.findByAccount(account.getAccount()) == null){
flag = this.dao.doCreate(account) ;
}
}catch(Exception e){
throw e ;
}finally{
this.dbc.close() ;
}
return flag ;
}
public String findByAccount(String acname) throws Exception{
String password = null ;
try{
password = this.dao.findByAccount(acname) ;
}catch(Exception e){
throw e ;
}finally{
this.dbc.close() ;
}
return password ;
}
}
package factory;
import DAO.IAccountDAO;
import DAO.AccountDAOProxy;
import DAO.IUploadFileDAO;
import DAO.UploadFileDAOProxy;
public class DAOFactory {
public static IAccountDAO getIAccountDAOInstance() throws Exception{ //取得DAO接口实例
return new AccountDAOProxy(); //取得代理类实例
}
public static IUploadFileDAO getIUploadFileDAOInstance() throws Exception{
return new UploadFileDAOProxy();
}
}
不要问我为什么这么多类这么麻烦。。这是小项目看起来是很麻烦,如果是大项目的话这样就更方便了。
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import md5.MD5;
import factory.DAOFactory;
import VO.Account;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RegisterServlet extends HttpServlet { //注册账号
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
Account account = new Account() ;
account.setAccount(request.getParameter("account"));
try {
account.setPassword(MD5.generateCode(request.getParameter("password")));
} catch (Exception e1) {
e1.printStackTrace();
}
try{
if(DAOFactory.getIAccountDAOInstance().doCreate(account)){ //执行添加操作
out.print("注册成功!");
} else {
out.print("该用户已被注册!");
}
}catch(Exception e){
e.printStackTrace() ;
out.print("注册失败!");
}
}
}
package md5;
import java.security.MessageDigest;
public class MD5 {
public static String generateCode(String str) throws Exception{ //MD5加密
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] srcBytes = str.getBytes();
md5.update(srcBytes);
byte[] resultBytes = md5.digest();
String result = new String(resultBytes);
return result;
}
}
以上就能成功地注册了。
既然能注册了,也就能登录了。
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;
import factory.DAOFactory;
import VO.Account;
import md5.MD5;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet { //验证账号密码
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
String account = request.getParameter("account");
try {
String password = MD5.generateCode(request.getParameter("password"));
if(DAOFactory.getIAccountDAOInstance().findByAccount(account).equals(password)){
request.getSession().setAttribute("account", account);
response.sendRedirect("toIndex.jsp");
}else{
out.print("账号或密码不正确");
}
}catch(Exception e){
e.printStackTrace() ;
out.print("登录错误");
}
}
}
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
正在登录……
为什么不直接跳到主页呢?因为我在登录页面写了AJAX,使LoginServlet的输出显示在登录页上,比如密码错时就把”账号或密码不正确“显示在登录页。但是登录成功时如果直接跳转到Index.jsp会让首页显示在登录页那里。所以设置一个过渡页面,然后再通过标签跳转到首页。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%@ page import="factory.DAOFactory" %>
<%@ page import="VO.UploadFile" %>
<% request.setCharacterEncoding("utf-8"); %>
WormJam-首页
<%
String account = (String)session.getAttribute("account");
out.println("欢迎你," + account);
%>
退出登录
上传我的源代码
${msg }
热门分享
文件名
作者
描述
下载
<%
List all = DAOFactory.getIUploadFileDAOInstance().findAll();
Iterator iter = all.iterator();
while(iter.hasNext()){
UploadFile file = iter.next();
out.println("");
out.println("" + file.getFileName() + " ");
out.println("" + file.getAccount() + " ");
out.println("" + file.getDescription() + " ");
out.println("下载");
out.println(" ");
}
%>
在首页,可以上传文件,然后再热门分享中把所有文件以及上传文件的作者列出来。我这里没有遍历文件夹来列出文件,而是在上传文件的同时记录到数据库。因此还应建立上传文件的DAO类。
package VO;
public class UploadFile { //用户上传文件的类
private String account;
private String fileName;
private String description;
public String getAccount(){
return account;
}
public void setAccount(String account){
this.account = account;
}
public String getFileName(){
return fileName;
}
public void setFileName(String fileName){
this.fileName = fileName;
}
public String getDescription(){
return description;
}
public void setDescription(String description){
this.description = description;
}
}
定义了文件名,作者及描述。
package DAO;
import java.util.* ;
import VO.UploadFile;
public interface IUploadFileDAO {
public boolean doCreate(UploadFile file) throws Exception; //写入
public List findByAccount(String account) throws Exception; //按账号查找文件
public List findAll() throws Exception; //列出所有文件
}
package DAO ;
import java.util.* ;
import java.sql.* ;
import DAO.IUploadFileDAO;
import VO.UploadFile;
public class UploadFileDAOImpl implements IUploadFileDAO {
private Connection conn = null; //数据库连接对象
private PreparedStatement pstmt = null; //数据库操作对象
public UploadFileDAOImpl(Connection conn){ //通过构造方法取得数据库连接
this.conn = conn;
}
public boolean doCreate(UploadFile file) throws Exception{ //添加账户
boolean flag = false; //定义标志位
String sql = "INSERT INTO FILES(acname,file,descript) VALUES (?,?,?)";
this.pstmt = this.conn.prepareStatement(sql); //实例化PrepareStatement对象
this.pstmt.setString(1,file.getAccount());
this.pstmt.setString(2,file.getFileName());
this.pstmt.setString(3, file.getDescription());
if(this.pstmt.executeUpdate() > 0){ //如果有更新操作
flag = true ;
}
this.pstmt.close() ;
return flag ;
}
public List findByAccount(String acname) throws Exception{//按账号查找密码
List all = new ArrayList();
String sql = "SELECT FILE,descript FROM FILES WHERE acname=?" ;
this.pstmt = this.conn.prepareStatement(sql) ;
this.pstmt.setString(1,acname);
ResultSet rs = this.pstmt.executeQuery() ;
UploadFile file = null;
while(rs.next()){
file = new UploadFile();
file.setFileName(rs.getString(1));
file.setDescription(rs.getString(2));
all.add(file);
}
this.pstmt.close();
return all;
}
public List findAll() throws Exception { //查找所有
List all = new ArrayList();
String sql = "SELECT * FROM FILES";
this.pstmt = this.conn.prepareStatement(sql) ;
ResultSet rs = this.pstmt.executeQuery() ;
UploadFile file = null;
while(rs.next()){
file = new UploadFile();
file.setAccount(rs.getString(1));
file.setFileName(rs.getString(2));
file.setDescription(rs.getString(3));
all.add(file);
}
this.pstmt.close();
return all;
}
}
package DAO ;
import java.util.* ;
import java.sql.* ;
import DAO.UploadFileDAOImpl;
import DAO.IUploadFileDAO;
import dbc.DatabaseConnection;
import VO.UploadFile;
public class UploadFileDAOProxy implements IUploadFileDAO {
private DatabaseConnection dbc = null ;
private IUploadFileDAO dao = null ;
public UploadFileDAOProxy() throws Exception { //在构造方法中实例化连接,同时实例化dao对象
this.dbc = new DatabaseConnection() ;
this.dao = new UploadFileDAOImpl(this.dbc.getConnection()) ;
}
public boolean doCreate(UploadFile file) throws Exception{
boolean flag = false ;
try{
flag = this.dao.doCreate(file) ;
}catch(Exception e){
throw e ;
}finally{
this.dbc.close() ;
}
return flag ;
}
public List findByAccount(String acname) throws Exception{
List all = null;
try{
all = this.dao.findByAccount(acname) ;
}catch(Exception e){
throw e ;
}finally{
this.dbc.close() ;
}
return all ;
}
public List findAll() throws Exception{
List all = null;
try{
all = this.dao.findAll() ;
}catch(Exception e){
throw e ;
}finally{
this.dbc.close() ;
}
return all ;
}
}
然后就可以上传文件了,并且上传成功后会把文件名,作者,和描述保存在数据库。上传文件需要用到jsmartcom包,而且我在解决上传的文件名乱码这一块花了很长时间,注意,我的项目里所使用的都是utf-8编码。有些jsmartcom包不支持中文,可以下载到别人改过的支持中文的包。
package servlets;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import factory.DAOFactory;
import VO.UploadFile;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpSession;
import com.jspsmart.upload.File;
import com.jspsmart.upload.SmartUpload;
import com.jspsmart.upload.SmartUploadException;
public class UploadServlet extends HttpServlet { //上传文件时的处理
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
UploadFile uploadfile = new UploadFile();
HttpSession session = request.getSession();
String account = (String)session.getAttribute("account"); //获取session中的用户名
uploadfile.setAccount(account);
SmartUpload smartUpload = new SmartUpload();
ServletConfig config = this.getServletConfig();
smartUpload.initialize(config, request, response);
try{
smartUpload.upload();
String text = smartUpload.getRequest().getParameter("text");
uploadfile.setDescription(text);
File smartFile = smartUpload.getFiles().getFile(0);
String fileName = smartFile.getFileName();
smartFile.saveAs("/files/" + fileName,smartUpload.SAVE_VIRTUAL);
request.setAttribute("msg", "上传成功!");
uploadfile.setFileName(fileName);
DAOFactory.getIUploadFileDAOInstance().doCreate(uploadfile);
}catch(SmartUploadException e){
request.setAttribute("msg", "上传失败!");
e.printStackTrace();
} catch (Exception e) {
request.setAttribute("msg", "上传失败!");
e.printStackTrace();
}
RequestDispatcher rd = request.getRequestDispatcher("/index.jsp");
rd.forward(request, response);
}
}
需注意,session中的用户名是在登录成功时设置的,我用一个session登录验证的过滤器来确保用户只有在登录的时候能够访问主页等页面,不然跳到登录页面:
package filters;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
public class LoginFilter implements Filter { //登录验证过滤器
public void init(FilterConfig config) throws ServletException{}
public void doFilter(ServletRequest request,ServletResponse response,
FilterChain chain) throws IOException,ServletException{
HttpServletRequest req = (HttpServletRequest)request;
HttpSession ses = req.getSession();
if(ses.getAttribute("account")!=null){
chain.doFilter(request, response);
}else{
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
public void destroy(){}
}
而点击页面上方的”退出登录“时,就要删除session中的用户,并跳到登录页:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%
session.removeAttribute("account");
response.sendRedirect("login.jsp");
%>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%@ page import="factory.DAOFactory" %>
<%@ page import="VO.UploadFile" %>
<% request.setCharacterEncoding("utf-8"); %>
WormJam-我的上传
我的上传
文件名
描述
下载
<%
List all = DAOFactory.getIUploadFileDAOInstance().findByAccount(account);
Iterator iter = all.iterator();
while(iter.hasNext()){
UploadFile file = iter.next();
out.println("");
out.println("" + file.getFileName() + " ");
out.println("" + file.getDescription() + " ");
out.println("下载");
out.println(" ");
}
%>
hisUpload.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" %>
<%@ page import="factory.DAOFactory" %>
<%@ page import="VO.UploadFile" %>
<% request.setCharacterEncoding("utf-8"); %>
WormJam-他的上传
<%= acname + "的上传" %>
文件名
描述
下载
<%
List all = DAOFactory.getIUploadFileDAOInstance().findByAccount(acname);
Iterator iter = all.iterator();
while(iter.hasNext()){
UploadFile file = iter.next();
out.println("");
out.println("" + file.getFileName() + " ");
out.println("" + file.getDescription() + " ");
out.println("下载");
out.println(" ");
}
%>
最后补充一点,点击下载时会新开一个页面显示文件的内容,而右键“下载”点击“链接另存为”时才会下载,特别是如果文件是zip等不能查看的类型就会出错。也有使点击就能下载的方法,我比较懒就没去试了。
x00-x7f ↩︎