jsp日记博客系统01

一、需求分析

1、日记列表显示
2、日记分类
3、个人中心–头像和标语
4、日记增删改

数据库3张表:
user
diary
diaryType
注意:主外键关联

二、登陆界面实现

首先需要登陆必须与数据库用户表进行数据通信,在数据库用户表中存入用户名和密码模拟注册。

建立util包,建立数据库工具类–连接数据库–关闭数据库。

建立dao包,建立UserDao.java与数据库通信–查询数据库登陆。
rs.next()为true则表示查到数据

建立web包,建立LoginServlet.java处理登陆请求。
servlet类需要继承httpServlet类,重写doPost和doGet方法,doGet调用doPost。
由于是请求,前端将用户名和密码发过来,这里获取下然后进行数据库查询,若存在则将用户对象存入session然后【客户端跳转mainTemp.jsp】,不存在则将错误用户名和密码及错误信息存入req然后【服务器跳转login】,此时login可以从req中获取刚才填入的信息。

引入Bootstrap
下载Bootstrap包放在WebContent目录下,在bootstrap/js下添加jQuery.js
jsp页面添加引用信息

web.xml修改首页为login.jsp

bootstrap流式栈布局包含12个栅格

login.jsp表单提交,action为login,故在web.xml配置servlet:

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>com.java.web.LoginServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

提交时候验证:onsubmit=”return checkForm()”
checkForm()为js函数。onsubmit为false,则不提交表单。

  <script type="text/javascript">
    function checkForm(){
        var userName=document.getElementById("userName").value;
        var password=document.getElementById("password").value;
        if(userName==null||userName==""){
            document.getElementById("error").innerHTML="用户名不能为空";
            return false;
        }
        if(password==null||password==""){
            document.getElementById("error").innerHTML="密码不能为空";
            return false;
        }
        return true;
    }
</script>

优化:采用properties存放系统配置项,容易维护
properties文件采用键值对形式存储数据:

url=jdbc:mysql://localhost:3306/db_blog?useSSL=false
driver=com.mysql.jdbc.Driver
userName=root
userPassword=123456

建立PropertiesUtil工具类–传入参数名,获得参数值

public static String getValue(String key) {
    Properties pro=new Properties();
    InputStream in=new PropertiesUtil().getClass().getResourceAsStream("/blog.properties");//以src为根
    try {
        pro.load(in);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return pro.getProperty(key);
}

优化:采用MD5加密密码
创建MD5Util工具类–传入字符串,获得加密字符串

public static String MD5Encode(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
    MessageDigest md5= MessageDigest.getInstance("md5");
    //jdk1.8
    //java.util.Base64.getEncoder().encodeToString("进制)//编码
    //java.util.Base64.getDecoder().decode(字符串内容)//解码
    return Base64.getEncoder().encodeToString((md5.digest(str.getBytes("utf-8"))));
}

记住用户名和密码
当登陆页面login.jsp上的记住勾选,则在登陆成功时需要记住用户名和密码到cookie中。

private void rememberToCookie(String userName, String password, HttpServletResponse resp) {
    Cookie user=new Cookie("user", userName+"-"+password);
    user.setMaxAge(1*60*60*24*7);
    resp.addCookie(user);
}

cookie单位是秒
记住了密码后下次登陆需要显示出来,而当用户输入错误用户名和密码时不需要显示cookie

<%
    if(request.getAttribute("user")==null){
        String userName=null;
        String password=null;

        Cookie[] cookies=request.getCookies();
        for(int i=0;cookies!=null&&i<cookies.length;i++){
            if("user".equals(cookies[i].getName())){
                userName=cookies[i].getValue().split("-")[0];
                password=cookies[i].getValue().split("-")[1];
            }
        }
        if(userName==null){
            userName="";
        }
        if(password==null){
            password="";
        }
        pageContext.setAttribute("user", new User(userName,password));
    }
%>

注意:需要import=”com.java.model.User,因为在java中需要访问User

三、主界面搭建及用户请求过滤

主界面搭建

引入自己的css:

<link href="${pageContext.request.contextPath}/style/blog.css" rel="stylesheet">

注意:css文件不需要头信息,直接写样式即可

导航:采用流式栈,左9右3

在前台直接定义好框架,获取req的变量来填充,使用

<jsp:include page="${mainDiary }"></jsp:include>

来动态获取值,先
login.jsp-login-loginservlet-main-mainservlet-mainTemp.jsp
在mainservlet中,将查询好的diaryList放入req,diaryList.jsp从req获取,然后mainTemp.jsp中取diaryList.jsp,这样完成动态获取。

请求过滤

拦截器Filter–httpservlet下的Filter
web.xml配置Filter:

<filter>
    <filter-name>loginFilter</filter-name>
    <filter-class>com.java.filter.LoginFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>loginFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

重写方法doFilter,转换下req,resp

HttpServletRequest req=(HttpServletRequest)sreq;
HttpServletResponse resp=(HttpServletResponse)sresp;
HttpSession session=req.getSession();

判断流程:若当前session无用户,则返回login.jsp,注意排除掉login.jsp,因为这个界面无需过滤:

if(obj==null&&path.indexOf("login")<0) {//若此时请求mainTemp.jsp会出错
    resp.sendRedirect("login.jsp");
}else {
    filter.doFilter(sreq, sresp);
}

可以调试使用:String path=req.getServletPath();来查看请求的地址

四、日记列表显示和分页实现

先导入数据库数据,来模拟已建好的日记和类别

日记列表显示

由于需要引入日记,这里建立一个日记model和日记dao–查询日记列表
查询函数:
–为了方便扩展使用【拼接字符串】方式构建查询语句
–为了方便显示日记类别等使用【连接查询】连接两张表查询
–由于数据库date类别和java的util里date不同,所以不能直接setReleaseDate,这里采用一个DateUtil工具类进行转换,在数据库获取时获取date字符串形式,通过工具转换成util date类型赋值。

public List<Diary> diaryList(Connection con)throws Exception{
    List<Diary> diaryList=new ArrayList<Diary>();
    StringBuffer sb=new StringBuffer("select * from t_diary t1,t_diaryType t2 where t1.typeId=t2.diaryTypeId ");
    sb.append(" order by t1.releaseDate desc");
    PreparedStatement pstmt=con.prepareStatement(sb.toString());
    ResultSet rs=pstmt.executeQuery();
    while(rs.next()){
        Diary diary=new Diary();
        diary.setDiaryId(rs.getInt("diaryId"));
        diary.setTitle(rs.getString("title"));
        diary.setContent(rs.getString("content"));
        diary.setReleaseDate(DateUtil.formatString(rs.getString("releaseDate"), "yyyy-MM-dd HH:mm:ss"));
        diaryList.add(diary);
    }
    return diaryList;
}

引用上面流程:login.jsp-login-loginservlet-main-mainservlet-mainTemp.jsp
mainservlet负责mainTemp.jsp页面的显示后台处理,在这里查询获取日记列表,并存入req中。

diaryList.jsp中构建前台日记列表显示:使用bootstrap的列表组建,采用【c标签和fmt标签】,前者负责遍历diaryList列表值,后者负责日期格式化操作。

<div class="diary_datas">
    <ul>
        <c:forEach var="diary" items="${diaryList }">
            <li><fmt:formatDate value="${diary.releaseDate }" type="date" pattern="yyyy-MM-dd"/><span>&nbsp;<a href="#">${diary.title }</a></span></li>
        </c:forEach>
    </ul>
</div>

分页

采用bootstrap分页组件来构建前台代码,分页中的每页项由后台构建

<div class="pagination pagination-centered">
    <ul>
        ${pageCode }
    </ul>
</div>

需要分页,则必须知道当前日记列表能分成多少页,这依赖于每页显示的列表数,在查询过程中,可以查询出所有列表,然后利用【limit】限制查询结果,结合当前页,决定显示的是哪些数据
起始数据=(当前页-1)*每页大小
查询长度=每页大小

修改diaryList函数,传入所需参数:如起始数据和查询长度,返回一页数据
修改MainServlet.java,调用日记列表查询函数时给所需要的值,可以将每页大小存到配置项中
MainServlet.java新增分页项输出函数,传入–当前页–总页数–每页大小
总页数可计算:int totalPage=totalNum%pageSize==0?totalNum/pageSize:totalNum/pageSize+1;
开始拼字符串:

StringBuffer pageCode=new StringBuffer();
pageCode.append("<li><a href='main?page=1'>首页</a></li>");
if(currentPage==1){
    pageCode.append("<li class='disabled'><a href='#'>上一页</a></li>");
}else{
    pageCode.append("<li><a href='main?page="+(currentPage-1)+"'>上一页</a></li>");
}
for(int i=currentPage-2;i<=currentPage+2;i++){
    if(i<1||i>totalPage){
        continue;
    }
    if(i==currentPage){
        pageCode.append("<li class='active'><a href='#'>"+i+"</a></li>");
    }else{
        pageCode.append("<li><a href='main?page="+i+"'>"+i+"</a></li>");
    }
}
if(currentPage==totalPage){
    pageCode.append("<li class='disabled'><a href='#'>下一页</a></li>");
}else{
    pageCode.append("<li><a href='main?page="+(currentPage+1)+"'>下一页</a></li>");
}
pageCode.append("<li><a href='main?page="+totalPage+"'>尾页</a></li>");
return pageCode.toString();

五、日记归类

日记类别归类

新建日记类别model,根据需求需要显示日记类别下的数量,所以添加第三属性为日记数量
新建日记类别dao–返回日记类别列表
注意:此处不能使用内连接查询,因为当类别下无日记数据时,该类别不会显示,采用【外连接查询】
采用右连接查询:right join:

SELECT typeName,typeId,COUNT(typeId) FROM t_diary RIGHT JOIN t_diarytype ON t_diary.`typeId`=t_diarytype.`diaryTypeId` GROUP BY typeName

MainServlet.java中将查询到的结果(日记类别和该类数量)放入session中,可以跨模块显示
在前台mainTemp.jspt中的日记类别栏进行c标签遍历输出查询结果

日记日期归类

mysql日期格式化函数:DATA_FORMAT(xxx,’%Y年%m月’),可以将xxx日期类型转换为后面的格式,降序DESC

String sql="SELECT DATE_FORMAT(releaseDate,'%Y年%m月') as releaseDateStr ,COUNT(*) AS diaryCount  FROM t_diary GROUP BY DATE_FORMAT(releaseDate,'%Y年%m月') ORDER BY DATE_FORMAT(releaseDate,'%Y年%m月') DESC;";

DiaryDao.java新建查询日记日期和数量查询函数

MainServlet.java中查询出日记日期和数量,放入session中
在前台mainTemp.jsp中的日记类别栏进行c标签遍历输出查询结果

六、日志主页完成

个人信息功能

将数据库user表信息完善,存入昵称、头像文件名、标语
建立头像文件夹,存放头像
增加头像文件地址配置参数

修改mainTemp.jsp,从currentUser中获取个人数据

修改UserDao.java,将后三者在登陆函数查询到用户时,一同存入user返回,而LoginServlet.java在登陆时调用了该函数并将结果存入currentUser变量中

右侧栏分类点击,日记列表改变

在右侧c标签遍历中,加入a标签的链接:
日志类别:

<li><span><a href="main?s_typeId=${diaryTypeCount.diaryTypeId }">${diaryTypeCount.typeName }(${diaryTypeCount.diaryCount })</a></span></li>

日志日期:

<li><span><a href="main?s_releaseDateStr=${diaryCount.releaseDateStr }">${diaryCount.releaseDateStr }(${diaryCount.diaryCount })</a></span></li>

引用上面流程:login.jsp-login-loginservlet-main-mainservlet-mainTemp.jsp
带的参数会在点击mainTemp.jsp链接时请求main,即跳到mainservlet中,可以在其中获取
修改mainservlet,在其中获取上面设置的两个值,若非空,则将其添加到一个diary实例中,并存入session中(方便翻页组建查看页数等)
修改diarydao,获取日记列表函数、获取日记数量函数加入diary输入,用来传入查询条件
–获取日记列表函数:判断传入diary的id或者releasedate是否为空,非空说明存入了值,拼接查询语句:and…
注意:当两个分类都点击过,session中保存两个查询条件,此时需要采用互斥,清除另外一个条件。
注意:通过url传递的字符串参数需要重新编码:s_releaseDateStr=new String(s_releaseDateStr.getBytes(“ISO-8859-1”),”UTF-8”);

搜索

当使用搜索时,默认查询所有符合条件的项,需要清除右侧session中的条件。
点击查询按钮,跳转main?all=true,带入参数all,且提交表单,获取表单输入文本框的信息,直接String s_title=request.getParameter(“s_title”);获取文本内容
当点击提交表单在mainservlet.java判断:

if("true".equals(all)){
    if(StringUtil.isNotEmpty(s_title)){
        diary.setTitle(s_title);
    }
    session.removeAttribute("s_releaseDateStr");
    session.removeAttribute("s_typeId");
    session.setAttribute("s_title", s_title);
}

若表单内容不为空,则模糊查询,加入到diarydao.java中的日记列表显示函数中:

if(StringUtil.isNotEmpty(s_diary.getTitle())){
    sb.append(" and t1.title like '%"+s_diary.getTitle()+"%'");
}

此时点搜索框已经可以查出数据,但是点击分页依然有问题,原因是分页组件请求时,查询到的total依然为总日记数,需要在【diarydao.java.diarycount函数中也加入模糊查询】,返回当前查询结果的总数。在mainservlet.java中判断语句加上:

if(StringUtil.isEmpty(s_title)){
    Object o=session.getAttribute("s_title");
    if(o!=null){
        diary.setTitle((String)o);
    }
}

确保分页组件请求时能获取到s_title变量
完成搜索功能。

猜你喜欢

转载自blog.csdn.net/xiapi3/article/details/81603511