JavaWEB十五:QQzone项目的整体分析及web关键点总结

QQzone项目的整体分析及web关键点总结

一、需求分析
1.熟悉QQZone业务需求
  1. 用户登录

  2. 登录成功,显示主界面。左侧显示好友列表;上端显示欢迎词。如果不是自己的空间,显示超链接:返回自己的空间;下端显示日志列表

  3. 查看日志详情:

    日志本身的信息(作者头像、昵称、日志标题、日志内容、日志的日期)

    回复列表(回复者的头像、昵称、回复内容、回复日期)

    主人回复信息

  4. 删除日志

    首先:确定浏览者是否是该日志的主人

    其次:确保日志内无任何回复,如果有,要删除所有回复

    最后:删除日志

  5. 删除特定回复

    首先:确定回复的author与浏览者是同一个人

  6. 删除特定主人回复

    首先:确定是主人在浏览该页面

  7. 添加日志、添加回复、添加主人回复

    添加主人回复时,要首先确定

  8. 点击左侧好友链接,进入好友的空间

    如果进入好友连接,要有“返回主人空间”的链接

二、数据库设计
  1. 抽取实体 :

    用户登录信息、用户详情信息 、 日志 、 回贴 、 主人回复

  2. 分析其中的属性:

    用户登录信息:账号、密码、头像、昵称

    用户详情信息:真实姓名、星座、血型、邮箱、手机号…

    日志:标题、内容、日期、作者

    回复:内容、日期、作者、日志

    主人回复:内容、日期、作者、回复

  3. 分析实体之间的关系

    用户登录信息 : 用户详情信息 1:1 PK

    用户 : 日志 1:N

    日志 : 回复 1:N

    回复 : 主人回复 1:1 UK

    用户 : 好友 M : N

    在这里插入图片描述

  4. 数据库的范式:

    第一范式:列不可再分
    第二范式:一张表只表达一层含义(只描述一件事情)
    第三范式:表中的每一列和主键都是直接依赖关系,而不是间接依赖

  5. 数据库设计的范式和数据库的查询性能很多时候是相悖的,我们需要根据实际的业务情况做一个选择:

    查询频次不高的情况下,我们更倾向于提高数据库的设计范式,从而提高存储效率

    查询频次较高的情形,我们更倾向于牺牲数据库的规范度,降低数据库设计的范式,允许特定的冗余,从而提高查询的性能

三、pojo中类的属性与数据表内字段的对应问题
  1. 数据表:各字段类型

    在这里插入图片描述

  2. pojo:各属性类型

    在这里插入图片描述

  3. author字段的类型不同的作用
    在数据库中:

    数据表t_topic中的author字段的类型是int型,这样可便与其它数据表之间形成对应关系

    在pojo中:

    author的属性类型是UserBasic,故author作为UserBasic类的一个实例对象,方便通过author调用UserBasic所对应的数据表t_user_basic中的字段。

  4. 在BaseDAO中:获取数据库字段中的自定义类型数据,如何转换后传入对应属性

    特别注意:所有的pojo中的属性名称除了自建类型,必须是Integer/String/Date,可被isMyType方法过滤,否则会报错,切记

    while (rs.next()) {
        // 4.4 处理该行记录的每一个字段
        // 4.4.1 创建该行记录在JavaBean中类的对象,此处用泛型实现
        T t = clazz.newInstance();
        // 4.4.2 利用通过元素据获得的结果集中列的个数,结合for循环对结果集中的列进行遍历
        for (int i = 0; i < columnCount; i++) {
            // 4.4.3 通过结果集对象获取该字段的值
            Object columnValue = rs.getObject(i + 1);
            // 4.4.4 通过元素据获取该字段的别(列)名,该列名与该行记录对应的对象中的属性名相同
            String columnLabel = rsmd.getColumnLabel(i+1);
    
            // 4.4.5 通过反射,给Customers对象中对应的属性赋值,实现将结果集中的数据存储到对象中
            Field field = clazz.getDeclaredField(columnLabel);
            // 4.4.6 如果属性是自定义类型,则需要将带有一个指定参数的自定义类的实例对象赋值给该对象
            // ① 获取属性的类型名称
            String typeName = field.getType().getName();
            // ② 判断该属性是否为自定义类
            if (MyTypeUtil.isMyType(typeName)){
                // ③ 如果是自定义类,就获取该自定义类的运行时类
                Class typeNameClass = Class.forName(typeName);
                // ④ 利用反射获取该自定义类的带Integer类型参数的构造器
                Constructor constructor = typeNameClass.getDeclaredConstructor(Integer.class);
                // ⑤ 将从数据库中提取的字段值传参进构造器,形成一个自定义类型的值
                columnValue = constructor.newInstance(columnValue);
            }
            // 确保私有属性可以访问
            field.setAccessible(true);
            // 利用给该字段对应的属性赋值
            field.set(t,columnValue);
        }               
    
  5. 自定义属性在html中的应用
    <td rowspan="2" class="w14 h96">
        <div class="h64 center " style="width:100%;">
            <img class="img56" th:src="@{|/imgs/${session.topic.author.headImg}|}"/>
        </div>
        <div class="h32 center" style="width:100%;"                           th:text="${session.topic.author.nickName}">乔峰</div>
    </td>
    
四、getparameter方法
  1. getParameter()是获取POST/GET传递的参数值。

    用于客户端重定向时,即点击了链接或提交按钮时传值用,即用于在用表单或url重定向传值时接收数据用。getParameter只是应用服务器在分析你送上来的request页面的文本时,取得你设在表单或url重定向时的值。

  2. 当两个Web组件之间为链接关系时,被链接的组件通过 getParameter()方法来获得请求参数。

    从 更深的层次考虑,request.getParameter()方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。request.getParameter()取得是通过容器的实现 来取得通过类似post,get等方式传入的数据。

  3. getParameter与getAttribute的区别

    getParameter系列的方法主要用于处理“请求数据”,是服务器端程序获取浏览器所传递参数的主要接口。getAttribute和setAttribute方法则向我们展示了HttpServletRequest对象如何在一次请求生命周期中完成对数据值的存储和访问的管理过程。其实该接口方式都是ServletRequest接口定义的,并不是Http仅有的。

五、关键节点总结
  1. 在controller内conn是threadLocal类型的
  2. Controller中:Servlet组件调用Controller的过程逻辑
    public class PageController {
        /*
            tomcat服务器的url:http://localhost:8080/page.do?operate=page&page=login
            业务层对applicationContext.xml的解析,将<bean>标签中的id-class以键值对的形式保存在beanMap中
            Servlet会解析url
                通过req.getServletPath,得到page.do,
                剥离“.do”后,再通过调用业务层的实例对象,获取beanMap中对应的PageController的实例对象
                通过req.getInitParameter("operate"),得到要调用的方法名page
                利用反射,获取PageController对象中的page方法的返回值,该方法的返回值
                通过返回值,从而将其组装成对应的html文件,该html文件中即可使用thymeleaf语言
         */
        public String page(String page)   {
            return page;
        }
    }
    
  3. Servlet组件内:获取controller内对应方法的返回值
     Method[] methods = controllersObj.getClass().getDeclaredMethods();
    for (Method method : methods) {
        if (operate.equals(method.getName())) {
            Parameter[] parameters = method.getParameters();
            // 创建一个Object数组,用于存放通过反射得到的各参数的对应值
            Object[] parameterValues = new Object[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[i];
                // 使用Parameter类的getName方法,获取该索引值对应参数的名称
                String parameterName = parameter.getName();
                // 将这些参数名赋给parameterValues数组
                if ("req".equals(parameterName)) {
                    parameterValues[i] = req;
                } else if ("resp".equals(parameterName)) {
                    parameterValues[i] = resp;
                } else if ("session".equals(parameterName)) {
                    parameterValues[i] = req.getSession();
                } else {
                    // 通过req,从请求参数中获取,与该参数名同名的参数的值,故contorller方法内的参数名要同html中的请求名称相同
                    String parameterValue = req.getParameter(parameterName);
                    String parameterType = parameter.getType().getName();
                    Object parameterValueObj = parameterValue;
                    if (parameterValueObj != null) {
                        if ("java.lang.Integer".equals(parameterType)) {
                            parameterValueObj = Integer.parseInt(parameterValue);
                        }
                    }
                    parameterValues[i] = parameterValueObj;
                }
            }
            method.setAccessible(true);
            Object returnObj = method.invoke(controllersObj, parameterValues);
    
  4. html文件跳转,必须要有target=“_top”
    <div id="top_link_div" >
        <span th:text="|欢迎进入${session.friend.nickName}的空间|"></span>
        <span th:if="${session.userBasic.id!=session.friend.id}" >
            <a th:href="@{|/user.do?operate=friend&id=${session.userBasic.id}|}" target="_top">返回自己的空间</a>
        </span>
    </div>
    
  5. 监听器、过滤器、组件上要有注解
  6. controller方法名和参数必须和tomcat中URL或html的< a>标签内的参数同名
  7. html内查错,可使用块:< span>
    <!-- headImg: 要检查代码的提示  故可在页面中查看该块处到底是什么显示情况,从而判断错误 -->
    headImg:<span th:text="@{|/imgs/${session.topic.author.headImg}|}"/>
    
  8. 表单提交数据时传参
    <!-- 表单提交的路径对应的controller -->
    <form action="reply.do" method="post">
         <!-- controller对应的方法 及 传入的参数 -->
         <input type="hidden" name="operate" value="addReply">
         <input type="hidden" name="topicId" th:value="${session.topic.id}">
    </form>
    
六、自己独自完成“主人回复”模块功能实现的思路
  1. 要实现回复功能,需要一个form表单,故要新建一个html
  2. 要实现addHostReply方法的,需要哪些参数
  3. 为实现传参,故有一部分参数保存在作用域中,故要对form表单所在的html文件进行组装,需调用pageController
  4. 在pageController中新建一个方法,该方法中可以先将部分参数保存在作用域中,然后组装html
  5. 在form表单中提交剩余的参数
  6. 利用传来的参数,在各个层创建一系列方法,将数据写入数据库
七、源代码

保存在个人CSDN博客的资源中,需要可免费下载

参考资料
  1. 构造器的作用和例子_Red sun的博客-CSDN博客_构造器的作用
  2. 在Java中对mysql数据库插入datetime类型数据_像风抓不住的博客-CSDN博客
  3. ( mysql的datetime类型在java中的存取_toMatser的博客-CSDN博客_mysql的datetime和java
  4. getParameter方法的用法_时间不会赖着不走的博客-CSDN博客_getparameter
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

e_nanxu

感恩每一份鼓励-相逢何必曾相识

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值