基于Servlet博客项论坛目开发过程《一》

注:本人是学习的新手,很多不懂得和很多要学习的,希望大家多多给建议,多多交流。

一.资料清单:

1.mysql必知会 

链接: https://pan.baidu.com/s/1UhwS-rHBio1ksk5fgUr1Ig 提取码: t2z4 

2.JSP&Servlet学习笔记(第二版)

链接: https://pan.baidu.com/s/1BJx2x00vTGegYXN0KunRlg 提取码: pwte 

3.powerdesigner安装包及破解文件

链接: https://pan.baidu.com/s/1-LzNG-fdSv07NOXKxiY2Aw 提取码: br7q 

4.PowerDesigner之PDM(物理概念模型)软件操作

链接: https://pan.baidu.com/s/1Ni3RxXGMgkkHm_myOAV4og 提取码: ts3u 

5.使用PowerDesigner画ER图详细教程

链接: https://pan.baidu.com/s/1mpv6gZ9-bIp-OXjpqLfQpg 提取码: y9np 

6.个人博客静态html资源

链接: https://pan.baidu.com/s/1jHGnCkTGf0AbJVgdniFsNQ 提取码: uiju 

7.intellij_ideal创建maven-Springmvc简单教程 

链接: https://pan.baidu.com/s/1e00nd1_PE3f5AIo6Wcc_QA 提取码: d44v 

8.ajax课程

链接: https://pan.baidu.com/s/1c1INKFHgrdxnqufzEAMD5g 提取码: fjna 

9.http协议

链接: https://pan.baidu.com/s/11q8AVZ3VqHDvFSp-XdDE-g 提取码: e5gm 

10.tomcat结构及处理请求过程。

链接: https://pan.baidu.com/s/1a2YcWY320QGzangOdtSPig 提取码: vu7v 

 


二.项目开发前概述

本来是我做C的终端开发的,工作内容比较简单,但是重复劳动力很多,且不能学习新的东西。后来公司出了Android智能终端,我就着手学习Android,一直到可以独立开发项目。随着时间慢慢过去,回首突然发现,这些前端的东西变化的太快了,而且随着微信小程序的普及和广泛使用,Andorid对于我的职业生涯规划来说也不是很好。我决定花时间来学习Java Web后端的开发。我知道这个周期会很长,但是只要能有进步的空间,我觉得这是很好的事情。

言归正传,我的学习过程其实也比较简单,百度查了下Web开发的路线,我找到了两个比较好的博客,文章都是坐着转载的找不到原地址了。

——Java和web方向的学习路线

      https://blog.csdn.net/yl1712725180/article/details/79329865#

——java学习路线图(2018年最新版)

      https://blog.csdn.net/chenshiyang0806/article/details/79879269

接下来就是学习了,通过数据库(mysql必知会)和servlet(Servlet学习笔记)的学习后,大致有了一个基本的概念,准备着手开发一个博客项目,来巩固自己的知识了。

 

直接上手写代码吧,很多东西不清晰,也不知道从何下手。百度了下,powerdesigner是一个很好的开发人员的模型工具,接下来就着手powerdesigner的学习,学习过程大概花了两三天左右的时间,上述资料清单里面有相关资料。

接着就使用powerdesigner来画物理模型,借鉴了CSDN~猫扑以及其他论坛网站的前端,完善了我的一些基本的模型。随着项目的推进,该项目的物理模型肯定会有变化的。目前的概念模型如下图。

学习powersigner了解了几种模型和它们之间的关系,以及一些基本的软件操作。当然目前只能说懂一点皮毛,不过这个的确是方便,开发项目的时候很有必要,建议大家学习下。学习的时候因为没有具体书籍,所以只能从网上找资料,我自己个人总结了一些基本的操作上上面的链接里。

学习powersigner之后,开始从网上找到了一个前端页面的例子(找这个资源花了半天时间,因为我觉得没有好的页面做出来的后端再好也没有啥用,所以美观的前端很重要,为了找到漂亮的,我愿意花半天时间专门找这个资源),在此感谢大神的分享(我只有一些前端的基础),在此例子的基础上开发,只能说有点难,前端的东西不是我能处理的。下图是这个静态资源的首页展示。

学习intellij ideal如何开发web项目(我之前学习的时候使用myeclipse,现在使用intellij ideal。intellij ideal开发起来太方便了,尤其是其优雅地代码提示,本人推荐使用intellij ideal。突然接触intellij ideal的时候也是一脸懵,不知道如何下手。狠心花了半天时间从网上找资料,琢磨了intellij ideal如何使用。现在终于能算是入门了。能好好开发我的项目了。

二.目前开过程

对前段做些简单处理吧,网上的资源虽然漂亮,但是重复代码太多,尤其一些head标签里面的内容,导航,底部等都是重复的,现在需要把这些内容抽取出来,我使用的是tag file来处理。另外我也针对我的博客功能修改和删除了一些东西。还有就是页面里面的内容都是英文的,算了,这个我用到哪里改到哪里吧,目前处理后大概是这个样子的。

导航栏,里面的数据项肯定要放数据库里面的,这样方便控制。下图是我的物理模型图具体内容。more字段是true的,就当把内容放入导航栏更多子菜单。对了,我对博客内容的一级分类叫区(学习猫扑)

获取导航栏的数据内容并展示在页面。此时发现了一个问题,就是每次加载页面的话都从数据库获取数据,这样会不会效率太慢,而且导航栏一般也不会随意改动,所以我增加了一个ServletContextListener,在应用启动的时候把获取到的数据塞入ServletContext的属性中。如果以后改动了导航栏数据,就修改下属性即可。这样每次直接从内存中获取他并展示在页面。

关于数据库操作DaoImpl类,我直接使用的jdbc没有使用任何框架,也是为了巩固jdbc的学习。在这里有个问题想请教下。我现在是定义了所有DaoImpl的基类BaseDaoImpl,里面是一些常用变量我给声明了程序变量,还有关闭操作我给提取出来了。

使用数据源来获取数据库连接。数据库的连接获取我也抽取出来了,我现在的思路是把Connection弄成static对象,这样保证所有的DaoImpl类使用的都是一个Connection资源,并且在获取Connection之前先判断它是否为空或者是否为关闭状态,如果是也通过数据源获得Connection,如果不是则直接返回当前Connection请大神看到了帮忙指正,这个问题仍然困扰着我。下面是我的基类代码。

package blog.dao.impl;

import blog.app.Constant;
import org.apache.log4j.Logger;

import javax.servlet.ServletContext;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * DAO实现类基类,获取连接,异常处理在这执行
 */
public class BaseDaoImpl {
    ServletContext context;

    //所有实例共享一个连接
    static Connection connection;
    PreparedStatement stmt;
    ResultSet rs;
    SQLException ex;

    public BaseDaoImpl(ServletContext context){
        this.context = context;
    }

    //获取Connection,如果连接已经关闭,则需要重新获得连接
    Connection getConn() throws SQLException {
        ex = null;
        if(connection == null || connection.isClosed()) {
            Logger.getLogger(BaseDaoImpl.class).info("数据库连接中...");
            DataSource dataSource = (DataSource) context.getAttribute(Constant.dataSource);
            connection = dataSource.getConnection();
        }
        return connection;
    }

    /**
     * 关闭资源
     * @param isConnClose-是否关闭数据库连接
     */
    void close(boolean isConnClose){
        if(rs != null){
            try {
                rs.close();
                rs = null;
            } catch (SQLException e) {
                if(ex == null) {
                    ex = e;
                }
            }
        }

        if(stmt != null){
            try {
                stmt.close();
                stmt = null;
            } catch (SQLException e) {
                if(ex == null) {
                    ex = e;
                }
            }
        }

        if(isConnClose && connection != null){
            try {
                connection.close();
                connection = null;
            } catch (SQLException e) {
                if(ex == null) {
                    ex = e;
                }
            }
        }


        if(ex != null) {
            Logger.getLogger(BaseDaoImpl.class).error(ex);
            throw new RuntimeException(ex);
        }
    }

    void rollback(){
        try {
            connection.rollback();
        } catch (SQLException e) {
            if(ex == null){
                ex = e;
            }
        }
    }

    void commit(){
        try {
            connection.commit();
        } catch (SQLException e) {
            if(ex == null){
                ex = e;
            }
        }
    }
}


下面是一个用户角色操作类源码

package blog.dao.impl;


import blog.dao.RoleDao;
import blog.model.Role;

import javax.servlet.ServletContext;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class RoleDaoImpl extends BaseDaoImpl implements RoleDao {
    public RoleDaoImpl(ServletContext context) {
        super(context);
    }

    @Override
    public Role getDefRole() {
        Role role = null;
        try {
            connection = getConn();
            stmt = connection.prepareStatement("SELECT id,name FROM role WHERE def = ?");
            stmt.setBoolean(1,true);
            rs = stmt.executeQuery();
            if (rs.next()){
                role = new Role();
                role.setId(rs.getString("id"));
                role.setName(rs.getString("name"));
            }
        } catch (SQLException e){
            ex = e;
        } finally {
            close(false);
        }
        return role;
    }

    @Override
    public void add(Role role) {
        try {
            connection = getConn();
            stmt = connection.prepareStatement("INSERT INTO role (id,name,def) VALUES (?,?,?)");
            stmt.setString(1,role.getId());
            stmt.setString(2,role.getName());
            stmt.setBoolean(3,role.isDef());
            stmt.executeUpdate();
        } catch (SQLException e) {
            ex = e;
        } finally {
            close(false);
        }
    }

    @Override
    public void delete(Role role) {
        try {
            connection = getConn();
            stmt = connection.prepareStatement("DELETE FROM role WHERE id = ?");
            stmt.setString(1,role.getId());
            stmt.executeUpdate();
        } catch (SQLException e) {
            ex = e;
        } finally {
            close(false);
        }
    }

    @Override
    public void update(Role role) {
        try {
            connection = getConn();
            stmt = connection.prepareStatement("UPDATE role SET name=?, def=? WHERE id = ?");
            stmt.setString(1,role.getName());
            stmt.setBoolean(2,role.isDef());
            stmt.setString(3,role.getId());
            stmt.executeUpdate();
        } catch (SQLException e) {
            ex = e;
        } finally {
            close(false);
        }
    }

    @Override
    public List<Role> getAll() {
        List<Role> roles = null;
        try {
            connection = getConn();
            stmt = connection.prepareStatement("SELECT id,NAME,def FROM role");
            rs = stmt.executeQuery();
            roles = new ArrayList<>();
            while (rs.next()) {
                Role role = new Role();
                role.setId(rs.getString("id"));
                role.setName(rs.getString("name"));
                role.setDef(rs.getBoolean("def"));
                roles.add(role);
            }
        } catch (SQLException e) {
            ex = e;
        } finally {
            close(false);
        }
        return roles;
    }
}

用户注册开发,先是改了前端的内容,唉一言难尽,搞了好久。基础的操作有了,通过网页能实现数据插入了。然后是完善的过程,这个过程有点复杂。第一个就是使用js来判断输入元素内容是否合适正确了,这个还好。然后ajax来判断用户名是否存在,邮箱是否被注册的功能了。ajax之前没有接触过啊,算了,花了一天的时间来学习,了解它是什么,基础操作,然后就是ajax的jquery的操作了。我是在菜鸟教程里面学习ajax的基础的。这个网上资料很多,能用就行了。我把学习的也给写成了word文档了,里面不包括jquery的ajax操作。等这些都没有问题后,再用js对密码进行MD5加密,传给后端。

然后是过滤器了,首先是字符编码过滤器(Html标签转义和敏感词过滤都在这里处理)。唉,说到这个,踩了一个深坑,我学习Servlet的时候url-pattern指定的都是/*,在这个项目我也是用的这个。然后继续编写其他过滤器和其他功能。等项目跑起来的时候,发现页面没有样式了。排查花了有半天时间(一直琢磨到半夜3点,还是第二天发现问题的),各种百度,各种尝试,最后甚至还重新建了项目来跑,都没有解决。唉…,跟踪log发现可能是我这个过滤器的原因,因为/*把加载js和css都进行过滤了。后来把url-pattern改成*.do和*.jsp就好了。 

敏感词过滤,首先也是在应用启动的时候,把敏感词放在内存,然后再处理的时候,直接从内存里面去取敏感词。接着就是如何优化敏感词的查找和替换时间了,这里再网上找了一会会资料。目前就先采用这个方案,速度还可以的。原文博客的连接找不到了,我就分享下现在的代码吧。

package blog.util;

import java.util.*;

/**
 * 敏感词过滤实现工具类
 */
public class DirtyWordUtil {
    private static StringBuilder replaceAll;//初始化
    private static String replaceStr = "*";//敏感词替代字符串
    private static int replaceSize = 500;


    static {
        replaceAll = new StringBuilder(replaceSize);
        for(int x=0;x < replaceSize;x++)
        {
            replaceAll.append(replaceStr);
        }
    }

    //过滤敏感词
    public static String filterDirty(String value, List<String> dirties)
    {
        HashSet<String> sensitiveWordSet = new HashSet<String>();
        List<String> sensitiveWordList= new ArrayList<>();
        StringBuilder buffer = new StringBuilder(value);
        HashMap<Integer, Integer> hash = new HashMap<Integer, Integer>(dirties.size());
        String temp;
        for(int x = 0; x < dirties.size();x++)
        {
            temp = dirties.get(x);
            int findIndexSize = 0;
            for(int start = -1;(start=buffer.indexOf(temp,findIndexSize)) > -1;)
            {
                //System.out.println("###replace="+temp);
                findIndexSize = start+temp.length();//从已找到的后面开始找
                Integer mapStart = hash.get(start);//起始位置
                if(mapStart == null || (mapStart != null && findIndexSize > mapStart))//满足1个,即可更新map
                {
                    hash.put(start, findIndexSize);
                    //System.out.println("###敏感词:"+buffer.substring(start, findIndexSize));
                }
            }
        }

        Collection<Integer> values = hash.keySet();
        for(Integer startIndex : values)
        {
            Integer endIndex = hash.get(startIndex);
            //获取敏感词,并加入列表,用来统计数量
            String sensitive = buffer.substring(startIndex, endIndex);
            //System.out.println("###敏感词:"+sensitive);
            if (!sensitive.contains("*")) {//添加敏感词到集合
                sensitiveWordSet.add(sensitive);
                sensitiveWordList.add(sensitive);
            }
            buffer.replace(startIndex, endIndex, replaceAll.substring(0,endIndex-startIndex));
        }
        hash.clear();
        return buffer.toString();
    }
}

 

发现加载页面有些慢,因为图片资源比较多嘛,就增加了压缩响应数据过滤器。编码是比较简单的,网上参考资料即可。在测试时候发现数据有的压缩后变小了,有的压缩后反而大了,百度了下知道了原因,所以在前人的基础上加了个判断。比较部分如下图。

暂时别的过滤器还没有处理,这个等以后用到了在增加。

再然后是登录页面忘记密码这个功能了。因为是学习,而且又不是为了赚钱,就暂且用邮箱找回密码功能吧。

这个没有碰到什么大坑,我使用的是自己的qq邮箱作为服务器邮箱了,百度了下怎么玩的,然后就操作了。邮件内容是什么格式是使用的一个简单的html模板来进行配置。 另外忘记密码的流程是,输入用户名和邮箱,先用ajax判断他们是否存在,不存在就不允许提交了。然后在后台判断用户名和邮箱是否匹配。匹配则先生成新的密码,更新数据库,发送邮件到用户邮箱。

完。后面每天做了什么都会在记录在微博。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值