第21章清爽夏日九宫格日记网
21.1 项目设计思路
21.1.1 功能阐述
显示九宫格日记列表模块
- 分页显示全部九宫格日记
- 分页显示我的日记
- 展开和收缩日记图
- 显示日记原图
- 对日记图片进行左转和右转
- 删除自己的日记等
写九宫格日记模块
- 填写日记信息
- 预览生成的日记图片
- 保存日记图片
用户模块
- 用户注册
- 用户登录
- 退出登录
- 找回密码
21.1.2 系统预览
后续放图
21.1.3 功能结构
访问者.pngA标记的部分,只有用户登录后,才可以操作的功能
21.1.4 文件夹组织结构
2.png21.2 数据库和数据表设计
21.2.1 数据库设计
创建数据库,新建两张数据表tb_user(用户信息表)
和tb_diary(日记表)
21.2.2 数据表设计
-
1.tab_user(用户信息表)
3.png
CREATE TABLE
tb_user
(
id
int(11) NOT NULL AUTO_INCREMENT,
username
varchar(50) NOT NULL COMMENT '用户名',
pwd
varchar(50) NOT NULL COMMENT '密码',
question
varchar(45) NOT NULL COMMENT '密码提示问题',
answer
varchar(45) NOT NULL COMMENT '提示问题答案',
city
varchar(30) NOT NULL COMMENT '所在地',
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
2.tb_diary(日记表)
4.png
CREATE TABLE
tb_diary
(
id
int(11) NOT NULL AUTO_INCREMENT,
title
varchar(60) DEFAULT NULL COMMENT '标题',
address
varchar(50) DEFAULT NULL COMMENT '日记保存的地址',
writeTime
datetime DEFAULT CURRENT_TIMESTAMP COMMENT '写日记时间',
userid
int(10) DEFAULT NULL COMMENT '用户ID',
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在设置数据表tb_diary时,还需要为字段writeTime设置默认值,这里为CURRENT_TIMESTAMP,也就是当前时间
21.3 公共模块设计
21.3.1 编写数据库连接及操作的类
public class ConnDB {
//声明Connection对象的实例
public Connection conn=null;
//声明Statement对象的实例
public Statement statement=null;
//声明ResultSet对象的实例
public ResultSet resultSet=null;
private static String propFileName="connDB.properties";//指定资源文件的保存位置
private static Properties properties=new Properties();//创建并实例化Properties对象的实例
private static String dbClassName="com.mysql.jdbc.Driver";//定义保存数据库驱动的变量
private static String dbUrl="jdbc:mysql://127.0.0.1:3306/db_9griddiary"
+ "?user=root&password=hwp123456&useUnicode=true";
//构造方法
public ConnDB(){
try {
//将Properties文件读取到InputStream对象中
InputStream in = getClass().getResourceAsStream(propFileName);
//通过输入流对象加载properties文件
properties.load(in);
//获取数据库驱动
dbClassName=properties.getProperty("DB_CLASS_NAME",dbClassName);
dbUrl=properties.getProperty("DB_URL",dbUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 连接数据库
* @return
*/
public static Connection getConnection() {
Connection connection=null;
try {
//装载数据库驱动
Class.forName(dbClassName).newInstance();
//建立与数据库URL中定义的数据库连接
connection=DriverManager.getConnection(dbUrl);
} catch (Exception e) {
e.printStackTrace();
}
if(connection==null){
System.out.println("数据库连接失败");
}
return connection;
}
/**
* 创建查询语句
* @param sql
* @return
*/
public ResultSet executeQuery(String sql){
try {
conn=getConnection();
statement=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
resultSet=statement.executeQuery(sql);
} catch (Exception e) {
System.err.println(e.toString());
}
return resultSet;
}
/**
* 创建执行更新操作的方法
* @param sql
* @return
*/
public int executeUpdate(String sql) {
int resukt=0;
try {
conn=getConnection();
statement=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
resukt=statement.executeUpdate(sql);
} catch (Exception e) {
e.printStackTrace();
}
return resukt;
}
/**
* 创建关闭数据库连接的方法
*/
public void close(){
try {
if(resultSet!=null){
resultSet.close();
}
if(statement!=null){
statement.close();
}
if(conn!=null){
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
21.3.2 编写保存分页代码的JavaBean
public class MyPagination {
public List<Diary> list=null;
private int recordCount; //保存记录总数的变量
private int maxPage; //保存最大页数的变量
private int pageSize; //保存每页显示的记录数的变量
/**
* 初始化分页信息
* @param list
* @param Page
* @param pageSize
* @return
*/
public List<Diary> getInitPage(List<Diary> list,int Page,int pageSize){
List<Diary> newList=new ArrayList<>();
this.list=list;
recordCount=list.size();
this.pageSize=pageSize;
this.maxPage=getMaxPage();
try {
for(int i=(Page-1)*pageSize;i<=Page*pageSize;i++){
try {
if(i>=recordCount){break;}
} catch (Exception e) {
e.printStackTrace();
}
newList.add(list.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}
return newList;
}
/**
* 获取指定页数据
* @param Page
* @return
*/
public List<Diary> getAppointPage(int Page){
List<Diary> newList=new ArrayList<>();
try {
for(int i=(Page-1)*pageSize;i<=Page*pageSize-1;i++){
try {
if(i>=recordCount){break;}
} catch (Exception e) {
e.printStackTrace();
}
newList.add(list.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}
return newList;
}
/**
* 获取最大记录数
* @return
*/
private int getMaxPage() {
int maxPage=(recordCount%pageSize==0)?(recordCount/pageSize):(recordCount/pageSize+1);
return maxPage;
}
/**
* 获取总记录数
* @return
*/
public int getRecordSize(){
return recordCount;
}
/**
* 获取页数
* @param str
* @return
*/
public int getPage(String str){
if(str==null){
str="0";
}
int Page=Integer.parseInt(str);
if(Page<1){
Page=1;
}else{
if(((Page-1)*pageSize+1)>recordCount){
Page=maxPage;
}
}
return Page;
}
/**
* 输出记录导航
* @param Page 当前页数
* @param url URL地址
* @param para
* @return
*/
public String printCtrl(int Page,String url,String para){
String strHtml="<table width='100%' border='0' cellspacing='0' cellpadding='0'><tr> <td height='24' align='right'>当前页数:【"+Page+"/"+maxPage+"】 ";
try{
if(Page>1){
strHtml=strHtml+"<a href='"+url+"&Page=1"+para+"'>第一页</a> ";
strHtml=strHtml+"<a href='"+url+"&Page="+(Page-1)+para+"'>上一页</a>";
}
if(Page<maxPage){
strHtml=strHtml+"<a href='"+url+"&Page="+(Page+1)+para+"'>下一页</a> <a href='"+url+"&Page="+maxPage+para+"'>最后一页 </a>";
}
strHtml=strHtml+"</td> </tr> </table>";
}catch(Exception e){
e.printStackTrace();
}
return strHtml;
}
}
21.3.3 配置解决中文乱码的过滤器
通常有两种方法解决程序中中文乱码
- 1.通过编码字符串处理类,对需要的内容进行转码
- 2.配置过滤器(推荐使用)
新建CharacterEncodingFilter类,实现Filter接口,成为一个Servlet过滤器
public class CharacterEncodingFilter implements Filter {
private String encoding=null; //定义编码格式变量
private FilterConfig filterConfig; //定义过滤器配置对象
@Override
public void destroy() {
encoding=null;
filterConfig=null;
}
//过滤器的接口方法,用于执行过滤业务
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if(encoding!=null){
request.setCharacterEncoding(encoding);//设置请求的编码
response.setContentType("text/html;charset="+encoding);
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
this.filterConfig=arg0;//初始化过滤器配置对象
this.encoding=filterConfig.getInitParameter("encoding");//获取配置文件中指定的编码格式
}
}
在web.xml中为CharacterEncodingFilter过滤器配置,关键代码如下
<filter>
<!-- 指定过滤器类型 -->
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.wgh.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
<!-- 设置过滤器对应的请求方式 -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
21.3.4 编写实体类
public class Diary {
private int id = 0;// 日记ID号
private String title = "";// 日记标题
private String address = "";// 日记图片地址
private Date writeTime = null;// 写日记的时间
private int userid = 0;// 用户ID
private String username = "";// 用户名
//省略所有的Setter()和Getter()方法
}
21.4 主界面设计
21.4.1 主界面概述
- Banner信息栏,主要用于显示网站的Logo
- 导航栏,主要用于显示网站的导航信息及欢迎信息,其中导航条目将根据是否是登录而显示不同的内容
- 主显示区,主要用于分页显示九宫格日记列表
- 版权信息栏,主要用于显示版权信息
21.4.2 让采用DIV+CSS布局的页面内容居中
- 1.在页面的<body>标记下方添加一个<div>标记(使用<div>标记将页面内容括起来),并设置其id属性
<div id="box">
</div>
- 2.设置CSS样式
body{
margin:0px; //外边距
padding:0px; //内边距
font-size:9pt; //设置字体大小
}
#box{
margin:0 auto auto auto; //设置外边距
width:800px; //宽度,其实这里宽度应该适配,写为auto
clear:both; //设置两侧边均不可以有浮动内容
background-color:#FFFFFF; //设置背景颜色
}
在JSP页面中,一定要包含以下代码,否则页面内容将不居中
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
21.4.3 主界面的实现过程
21.5 用户模块设计
21.5.1 用户模块概述
注册模块、登录模块截图
微信截图_20191021091724.png 微信截图_20191021091750.png
21.5.2 实现Ajax重构
- 1.创建一个单独的JS文件,名称为AjaxRequest.js,并且在该文件中编写重构Ajax所需的代码
var net=new Object(); //定义一个全局的变量
//编写构造函数
net.AjaxRequest=function(url,onload,onerror,method,params){
this.req=null;
this.onload=onload;
this.onerror=(onerror) ? onerror : this.defaultError;
this.loadDate(url,method,params);
}
//编写用于初始化XMLHttpRequest对象并指定处理函数,最后发送HTTP请求的方法
net.AjaxRequest.prototype.loadDate=function(url,method,params){
if (!method){
method="GET"; //设置默认的请求方式为GET
}
if (window.XMLHttpRequest){ //非IE浏览器
this.req=new XMLHttpRequest(); //创建XMLHttpRequest对象
} else if (window.ActiveXObject){//IE浏览器
this.req=new ActiveXObject("Microsoft.XMLHTTP"); //创建XMLHttpRequest对象
}
if (this.req){
try{
var loader=this;
this.req.onreadystatechange=function(){
net.AjaxRequest.onReadyState.call(loader);
}
this.req.open(method,url,true); // 建立对服务器的调用
if(method=="POST"){ // 如果提交方式为POST
this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); // 设置请求的内容类型
this.req.setRequestHeader("x-requested-with", "ajax"); //设置请求的发出者
}
this.req.send(params); // 发送请求
}catch (err){
this.onerror.call(this); //调用错误处理函数
}
}
}
//重构回调函数
net.AjaxRequest.onReadyState=function(){
var req=this.req;
var ready=req.readyState; //获取请求状态
if (ready==4){ //请求完成
if (req.status==200 ){ //请求成功
this.onload.call(this);
}else{
this.onerror.call(this); //调用错误处理函数
}
}
}
//重构默认的错误处理函籹
net.AjaxRequest.prototype.defaultError=function(){
alert("错误数据\n\n回调状态:" + this.req.readyState + "\n状态: " + this.req.status);
}
- 2.在需要应用Ajax页面中应用以下语句包括AjaxRequest.js的JS文件
<script language="javascript" src="JS/AjaxRequest.js"></script>
- 3.在应用Ajax的页面中编写错误处理的方法、实例化Ajax对象的方法和回调函数
21.5.3 用户注册的实现
1.设计用户注册页面
- 1.创建register.jsp页面,并在该页面上添加一个<div>标记,设置其id属性为register,并设置该<div>标记的style属性
<div id="register" style="width:663; height:421; background-color:#546B51; padding:4px; position:absolute; z-index:11;display:none;">
- 2.用户注册页面所涉及的表单及表单元素
|名称|元素类型|重要属性|含义|
|---------|---------|---------|---------|
|form1|form|action="" method="post"|表单|
|user|text|onBlur="checkUser(this.value)"|用户名|
|pwd|password|onBlur="checkPwd(this.value)"|密码|
|repwd|password|onBlur="checkRepwd(this.value)"|确认密码|
|email|text|onBlur="checkEmail(this.value)"|E-mail地址|
|province|select|id="province" onChange="getCity(this.value)"|省份|
|city|select|id="city"|市县|
|question|text|onBlur=“checkQuestion(this.value,this.form.answer.value)”|密码提示问题|
|answer|text|onBlur="checkQue(this.form.question.value,this.value)"|提示问题答案|
|btn_sumbit|buttom|value="提交" onClick="save()"|提交、按钮|
|btn_reset|button|value="重置" onClick="form_reset(this.form)"|重置、按钮|
|btn_close|button|value="关闭" onClick="Myclose('register')"|关闭、按钮| - 3.实现级联显示选择所在地省份和市县的下拉列表
- 4.编写自定义的JavaScript函数Regopen(),用于居中显示用户注册页面
//显示用户注册页面
function Regopen(divID){
getProvince(); //获取省和直辖市
var notClickDiv=document.getElementById("notClickDiv"); //获取id为notClickDiv的层
notClickDiv.style.display='block'; //设置层显示
document.getElementById("notClickDiv").style.width=document.body.clientWidth;
document.getElementById("notClickDiv").style.height=document.body.clientHeight;
divID=document.getElementById(divID); //根据传递的参数获取操作的对象
divID.style.display='block'; //显示用户注册页面
divID.style.left=(document.body.clientWidth-663)/2; //设置页面的左边距
divID.style.top=(document.body.clientHeight-441)/2; //设置页面的顶边距
}
- 5.在网站导航栏中设置用于显示用户注册页面的超链接,并在其onclick事件中调用Regopen()函数
<a href="#" onclick="Regopen('register')">注册</a>
- 6.编写自定义的JavaScript函数Myclose(),用于隐藏用户注册页面
//隐藏用户注册页面
function Myclose(divID){
document.getElementById(divID).style.display='none'; //隐藏用户注册页面
//设置id为notClickDiv的层隐藏
document.getElementById("notClickDiv").style.display='none';
}
2.验证输入信息的有效性
- 1.在验证输入信息的有效性,首先需要定义一下6个JavaScript全局变量
<script language="javascript">
var flag_user=true; //记录用户是否合法
var flag_pwd=true; //记录密码是否合法
var flag_repwd=true; //确认密码是否通过
var flag_email=true; //记录e-mail地址是否合法
var flag_question=true; //记录密码提示问题是否输入
var flag_answer=true; //记录提示问题答案是否输入
</script>
网友评论