【软创实验室大作业】学习小组网站

Java部分

封装一个数据结构,这里我选择了双向循环链表,也叫双链表。先简单介绍一下,双向循环链表的每个数据节点都有两个指针,分别指向直接后继直接前驱。所以,从双向链表的任意一个节点开始,都可以很方便地访问它的前驱节点和后继节点。

上学期刚学过C语言的数据结构,链表这一块用的还是比较多的,看一两个视频复习一下,用Java写起来也是比较快的,我一开始也没看到这个作业,一直在写JavaWeb的部分,最后花了大半天的时间写完。

1、编写接口

通过查看源码和数据结构的书籍,就大概可以知道实现一个数据结构需要编写什么方法,这里写了一个接口,会更加清楚明了一些,一个数据结构基本的方法都有实现。接口没有注释,实现类有较为详细的注释。

import java.util.Comparator;
import java.util.Iterator;

public interface List<E>  {

     void add(E element);

     void add(int index,E element);

     void remove(E element);

     E remove(int index);

     E get(int index);

     E set(int index ,E element);

     void clear();

     boolean contains(E element);
     
     int indexOf(E element);

     boolean isEmpty();

     int size();

     void sort(Comparator<E> c);

     List<E> subList(int fromIndex,int toIndex);

     Iterator<E> iterator();

}

2、方法实现

在实现方法之前肯定要定义一个节点和初始化一些东西

//链表的节点 使用private修饰
private class Node{
    private E data;
    //双向循环链表 前驱 和后继
    private Node pre;
    private Node next;
    //三个构造器
    public Node(){
        this(null,null,null);
    }

    public Node(E data){
        this.data=data;
        pre=null;
        next=null;
    }

    public Node(E data, Node pre, Node next) {
        this.data = data;
        this.pre = pre;
        this.next = next;
    }

    @Override
    public String toString() {
        return data.toString();
    }

}
//双向循环链表有头节点和尾节点
private Node head;//头节点
private Node tail;//尾节点
private int size;//链表的长度

//初始化
public LinkedList(){
    head=null;
    tail=null;
    size=0;
}

接下来就是一个个去实现链表的方法。

在涉及到index 的方法时,都要先判断是否在范围之内,否则就要抛出异常

        //判断index是否合法
        if(index<0||index>size){
            //抛出异常
            throw new IndexOutOfBoundsException("index out of range");
        }

sort方法里也有一个异常

    //排序
    @Override
    public void sort(Comparator<E> c) {
        if(c==null){
            throw new IllegalArgumentException("can not be null");
        }

方法具体的实现我就不细说了,这里展示一下测试的结果

image-20210821011316783

从测试结果可以看出该链表基本功能

JavaWeb

开发简述

​ 这次的大作业我差不多20天时间都没闲着,前面一段时间主要在学,真正写了一个星期的样子。主要使用HTML + CSS + JS + JQuery + Ajax + Servlet + JSP,运用MVC思想来分层设计,每个功能的实现一开始都比较困难,需要调试很久。写到后面就发现代码都是重复的,感觉这样写太麻烦了,Dao层,Service层和Servlet层,同时有些功能也实现不了。我就去学了JQuery和Ajax,还有一个Jquery的插件 Jquery Validate,这三个用的也比较多。通过这三者我利用JS实现了比较多的功能。JQuery是为了用Ajax学了一点,有些时候用的还是原生JS。JavaWeb我是跟着B站狂神学的,这个讲的有点乱我就自己去看博客看别人是怎么写的,从别人那里学会了很多解决问题的小技巧。

同时这次大作业最大的困难就是时间不够,我是在Ubuntu系统上开发的,之前集训的时候我的windows崩了,只好重装系统,随之而来的就是各种软件和环境变量的配置。于是我选择了Linux,安装软件方便也不用配置环境变量。但是调教和学习这个系统同样花了我很多的时间,因为有些软件安装起来比windows更麻烦一点。最折磨的就是ubuntu经常会出各自问题,Idea经常写到一半闪退导致代码丢失一部分,我至少1/3的时间在解决系统的问题。 就像今天本来是写这个文档的,系统就崩了,我搞了一天,终于能够启动了,在晚上11:59分把作业发到邮箱去了。

image-20210821015226300

那么多崩溃日志就离谱(本来我桌面上是没东西的,崩溃之后文件都跑到桌面上了,老毛病了),也不是Ubuntu的问题吧,可能我没有调教好,写完大作业就去解决。

功能简单描述

1.前后台

  • 前台主要做展示交互,首页和每个话题都有对应的页面。

  • 后台可以对完整进行管理设置,对学习小组,话题,评论,用户进行管理。根据管理对象不同,能够进行的操作也不同,比如用户可以增删改查,而评论我们一般只能查询和删除(也不能改别人的评论吧)。

  • 后台管理都设置了对应的查询关键字,可以方便的查询

2.权限管理

权限有两种:普通用户管理员

  • 普通用户登录后可以在前台浏览和评论,可以加入相应的学习小组

  • 管理员可以登录后台,可以对用户、学习小组、评论等进行管理

管理员点击登陆之后直接登陆到后台,普通用户登陆到前台

3.用户注册和登录

  • 注册:填写相关信息即可注册成功,管理员后台也可以添加用户。

  • 登录:输入正确的账号密码即可登录成功,没有登陆是无法前往前台的,因为这个学习小组类似实验室的官网一部分,需要学号登陆。

4.学习小组

学习小组下有许多话题讨论

不是小组成员也可以看话题讨论,但是只有是小组成员才能去创建话题

5.话题讨论

  • 小组成员创建话题,有标题和标题描述

  • 用户可以在话题下评论,也可以在评论下评论。

这么看着可能功能不多,但是我写的细节很多,功能之间都是串联起来的,例如删除一个小组,那么我不止删除这个小组,我也把这个小组下的话题和评论都删除了。 接下来详细介绍各个页面以及功能。

项目结构

技术栈: HTML + CSS + JS + JQuery + Ajax + Servlet + JSP

image-20210821081635479

image-20210821081822632

image-20210821081941901

image-20210821082051319

数据库结构

未命名文件

这个数据库还是比较符合三大范式的,这也导致我前台传入数据到后台查询返回需要多写许多步骤,例如comment表内只有创建用户的ID没有用户名,显示创建评论的用户名时需要多写几个步骤。

页面详细介绍

登陆注册页面

这个页面是我跟着b站上的学的,在写这个大作业之前 我是把b站上黑马前端的网课都看的差不多了,html+css+js,觉得美化页面还是挺有趣的。我自己写的前端也是花了很长时间去优化各种细节:按钮的hover,盒子的阴影等等

这个页面我是完全跟着视频敲的,我自己也写不出来这么厉害的页面,主要是CSS动画没这么多,视频只有不到一个小时,我自己敲花了一天,遇到看不懂的地方就要去查相应的用法。

在这里插入图片描述

首先是这个页面的HTML部分, 一开始引入了normalize.css,这个是从cdnjs上引入的( 一个好用的js在线库,比较快),就是重置CSS 用的,个人感觉跟初始化CSS代码作用类似。normalize有一些优点:保留有用的默认值,规范化各种元素的样式。更正错误和常见的浏览器不一致,通过细微的修改提高可用性等等。这个我没有下载,可能会加载一小会。

    <!-- 引入normalize css -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">

image-20210821083220218

然后这里有个图标

<!-- 引用 favicon图标 -->
<link rel="shortcut icon" href="images/bitbug_favicon(2).ico">

这个图标也是我特意去网上查怎么修改的。

主体部分就是一个注册的表单,一个登陆的表单,一个用于切换的浮层。最后背景就是从unsplash嫖来的壁纸,多个背景会自动切换。

这个页面主要就是动画比较流畅自然。

第一次加载可能需要一点点时间

登陆注册页面功能

  • 根据权限的不同,自动登录到前台或者后台
  • 可以注册用户,学号是唯一的,这里本来想实现发送邮件的功能,可惜我在测试的时候邮件经常发送失败,就删去了这个功能
  • 因为时间原因这里的注册没有检查学号的重复和确认密码,我在后台的创建用户利用AjaxJquery的一个插件实现了表单提交检验包括学号的重复问题

前台页面

这个页面是我自己纯手写的,有三个CSS文件,没有用到框架。

整体感觉比较大气美观的(把两个Test小组删掉就更好看了)

在这里插入图片描述

最上面的nav一栏,主要显示了用户名,首页和退出的按钮,两个Servlet搞定。考虑到大作业说是在实验室官网的背景下,那么官网肯定有很多功能,这样nav就不会只有这一点内容了。

image-20210821091058668

轮播图

接下来是一个网页的轮播图,这是我用JS纯手写的,这个的目的就是放一些热点话题或者新建了个小组用来宣传等等。

image-20210821091224872

写了大概有160行代码,功能还是非常完善的,自动播放,手动切换,并且比较流畅,篇幅原因我就不放代码出来了。这张图片点击可以直接跳转到对应的话题。

小组分类模块

image-20210821091753826

一开始进入首页没有选择分类那么,会加载所有小组的话题

image-20210821091935519

选择了一个小组可以加载对应的话题

image-20210821092043195

话题讨论模块

首先是创建话题,没有加入该小组的话是不能创建该小组下的话题的

image-20210821092130509

同样没有选择小组也是不能创建话题的

image-20210821092321948

确认是该小组的成员之后,点击就会出现一个文本域

image-20210821092412780

刚创建好话题自然没有评论,就会显示暂无评论

image-20210821092512931

侧边栏

右侧有一个固定的侧边栏

image-20210821093150916

三个功能:

  • 小组分类:直接跳转到小组分类进行选择
  • 话题讨论:跳转到第一条话题讨论
  • 加入小组:加入该小组

如果已经加入该小组弹出提示:

image-20210821093320491

如何实现

上述功能基本都是用Ajax实现的

<%
    if(request.getSession().getAttribute("groupId")==null){
%>
<script>

    document.querySelector('.makeTopic').addEventListener('click',function (){
        alert('请选择小组');
    });

    var member=document.querySelector('.addMember');
    member.addEventListener('click',function (){
        alert('请选择小组');
    });

</script>
<% }else{ %>
<script>
    var path1 = $("#path").val();
    var makeTopic=$(".makeTopic");
    var chosenGroup=document.querySelector('#groupId<%=request.getSession().getAttribute("groupId")%>');

    //改变选中小组的颜色
    chosenGroup.style.color='#0066ff';

    //创建话题 的提示
    function checkMember(obj){
        console.log('ajax------- checkMember ')
        $.ajax({
            type:"GET",
            url:path1+"/jsp/member.do",
            data:{method:"check"},
            dataType:"json",
            success:function(data){
                if(data.checkResult == "true"){
                   document.getElementById('inputbox').style.display='block';
                }else if(data.checkResult == "false"){
                    alert('请先加入该小组');
                }else if(data.checkResult == "noInfo"){
                    alert('该小组可能不存在')
                }
            },
            error:function(data){
                alert('对不起,无法创建')
            }
        });
    }
    $(function(){
        makeTopic.on("click",function(){
            var obj = $(this);
            checkMember(obj);
        });
    });

    //加入小组的提示
    function addMember(obj){
        console.log('ajax------- addMember ')
        $.ajax({
            type:"GET",
            url:path1+"/jsp/member.do",
            data:{method:"add"},
            dataType:"json",
            success:function(data){
                if(data.addResult == "success"){
                    alert('加入成功');
                }else if(data.addResult == "fail"){
                    alert('Sorry,加入失败')
                }else if(data.addResult == "noInfo"){
                    alert('该小组可能不存在')
                }else {
                    alert('已加入该小组!')
                }
            },
            error:function(data){
                alert('对不起,加入失败')
            }
        });
    }
    $(function(){
        $(".addMember").on("click",function(){
            var obj = $(this);
            addMember(obj);
        });
    });
</script>
<% } %>

下面就是Servlet Service Dao 这三层

这里将一下我怎么写的这三层,之后篇幅原因就不讲了

首先Servlet

我doGet里面通过前端传入的method参数,去调用对应的函数

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String method = request.getParameter("method");
        System.out.println("method:!!!!" + method);//调用什么方法

        if (method != null && method.equals("add")) {
            this.add(request, response);

        }else if(method!=null&&method.equals("query")){
            this.query(request,response);

        }else if(method!=null&&method.equals("number")){
            this.number(request,response);

        }else if(method!=null&&method.equals("deleteUser")){
            this.delete(request,response);
        }else if(method!=null&&method.equals("modify")){
            //通过用户id得到用户
            this.getUserById(request, response,"usermodify.jsp");
        }else if(method!=null&&method.equals("modifyFunc")){
            //
            this.modify(request,response);
        }
    }

例如这个add函数

   //增加用户
    private void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet ===>添加用户中");

        //前端获取参数
        String email = req.getParameter("email");
        String userName = req.getParameter("userName");
        String userPassword = req.getParameter("userPassword");
        String rl=req.getParameter("roleSel");
        Integer role=0;
        if (rl == null|| rl=="") {
            role=0;
        }else {
            role = Integer.parseInt(rl);
        }

        String studentNumber= req.getParameter("studentNumber");

        String fromPage=req.getParameter("fromPage");

        System.out.println(email+userName+userPassword+role+studentNumber);
        //把这些值方进一个用户中
        User user = new User();
        user.setEmail(email);
        user.setUserName(userName);
        user.setPassword(userPassword);
        user.setRole(role);
        user.setStudentNumber(studentNumber);

        UserServiceImpl userService = new UserServiceImpl();
        Boolean flag = userService.add(user);

        if (fromPage.equals("index")){
            resp.sendRedirect("login.jsp");
        }else{
            resp.sendRedirect("backstage.jsp");
        }

    }

这样做能够实现代码的复用

然后Service层没什么好讲的,Dao层下面有个BaseDao

有JDBCUtils的功能,也封装了增删改查操作

    //编写查询公共方法
    public static ResultSet execute(Connection connection,PreparedStatement preparedStatement, ResultSet resultSet ,String sql, Object[] params) throws SQLException {
        //预编译的sql,在后面直接执行就可以了
        preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            //setObject,占位符从1开始,但是我们的数组是从0开始!
            preparedStatement.setObject(i+1,params[i]);
        }

        resultSet = preparedStatement.executeQuery();
        return resultSet;
    }


    //编写增删改公共方法
    public static int execute(Connection connection,PreparedStatement preparedStatement,String sql,Object[] params) throws SQLException {
        preparedStatement = connection.prepareStatement(sql);

        for (int i = 0; i < params.length; i++) {
            //setObject,占位符从1开始,但是我们的数组是从0开始!
            preparedStatement.setObject(i+1,params[i]);
        }

        int updateRows = preparedStatement.executeUpdate();
        return updateRows;
    }

难点:

以上功能的难点就是前端美化打磨的挺长时间,编写了大量的Servlet方法 Service和Dao许多小细节也是卡了挺久,现在做完之后是感觉对这些非常熟练,没有什么难点了,当时写的话还是花了不少时间的。想要实现这些功能Ajax必不可少,不然点击一个按钮整个页面就要刷新一次,Ajax实现了异步处理,局部刷新,配合上Jquery使用起来一开始比较困难,后来就熟练了

话题讨论页面

image-20210821095421908

最上面的nav与首页一样

nav的下方就是话题的描述,发起人和创建评论按钮

创建评论

image-20210821095751241

这里有一个富文本编辑器 KindEditor插件,本来想自己写的,后来发现实现这个比较难,而且需要花很长时间,于是我就找了一个插件,也是琢磨了好久才成功使用。

这个编辑器可以上传图片链接,修改文字格式等等,上传文件与图片实现不了,因为我感觉上传文件这个功能对我现在个人来说比较麻烦,会出现许多问题,虽然我学了也写了demo。

image-20210821100451104

上传图片链接

多级评论模块

image-20210821100639610

在创建评论之后,用户可以在评论下方回复这个评论,如上图所示,有一个发布评论的文本框。

这里我好想理解错了多级评论的意思,我这里好像不能对二级评论进行回复,没看清要求大意了。但是原理是一样的利用comment表的pid(上级评论id)然后递归实现。这里我来不及实现了,最后一天了(系统还崩了),开学前我会慢慢完善的。

这里的文本框也是有些细节的:

image-20210821101232324

他的长度会根据内容来改变,要知道textarea是没有这个功能的,利用js才能实现

所以说我这个大作业细节还是比较多的,因为一些大网站(CSDN 知乎)也有这些功能,我尽量去模仿。

这样前台差不多就展示完毕了,接下来是后台的展示。

后台主页面

这个后台页面也是受狂神视频里的那个项目启发来写的,我上面的代码结构也是狂神说JavaWeb的风格,应该是比较规范的。

image-20210821101714902

用户管理

先看最重要的用户管理

image-20210821102256419

用户查询

点击查询可以进行模糊查询

image-20210821102440593

之后的每个管理模块都有这个功能就不去一个一个去展示了。

用户添加

image-20210821102603258

从红字可以看到,即时的表单校验,不用去刷新页面。这是通过JQuery的一个插件 Validate 。有一个检查学号重复的功能(系统通过学号登陆)是通过Ajax配合Validate 的remote实现的

$().ready(function() {
// 在键盘按下并释放及提交后验证提交表单
	$("#addUserFrom").validate({
		rules: {
			userName: {
				required: true,
				minlength: 3
			},
			studentNumber: {
				required: true,
				remote:{
					url: path+"/jsp/user.do",//后台处理程序
					type: "GET",               //数据发送方式
					data: {                     //要传递的数据
						studentNumber: function() {return $("#studentNumber").val();},
						method:"number"
					}
				}
			},
			userPassword: {
				required: true,
				minlength: 6
			},
			confirm_password: {
				required: true,
				minlength: 6,
				equalTo: "#userPassword"
			},
			email: {
				email: true
			},
			roleSel:{
				required:true
			}
		},
		messages: {
			userName: {
				required: "请输入用户名",
				minlength: "用户名最少由三个字符组成"
			},
			studentNumber: {
				required: "请输入学号",
				remote: "该学号已创建帐号!"
			},
			password: {
				required: "请输入密码",
				minlength: "密码长度不能小于 6 个字符"
			},
			confirm_password: {
				required: "请输入密码",
				minlength: "密码长度不能小于 6 个字母",
				equalTo: "两次密码输入不一致"
			},
			email: "请输入一个正确的邮箱",
			roleSel:{
				required:"请选择权限"
			},
		},
		submitHandler: function(form) {
			form.submit();
		}
	});
});

这个JQuery插件,非常的好用,也能配合上Ajax实现远程校验,如何使用我就不说了,看代码也能差不多看懂。

修改用户

跟添加用户差不多,只不过调用的servlet等等不同

image-20210821103323727

删除用户

image-20210821103437949

通过JS Ajax 实现的删除

点击弹出确认框,确认之后就会直接删除,并且页面不用进行刷新

function deleteUser(obj){
	$.ajax({
		type:"GET",
		url:path+"/jsp/user.do",
		data:{method:"deleteUser",userid:obj.attr("userid")},
		dataType:"json",
		success:function(data) {
			if (data.delResult == "true") {
                //删除成功:移除删除行
				obj.parents("tr").remove();
			} else if (data.delResult == "false") {
                //删除失败
				alert('删除失败')
			}
		},
		error:function(data){
			alert('删除失败')
		}
	});
}



$(function(){
	$(".deleteUser").on("click",function(){
		var obj = $(this);
		if(confirm('是否确认删除?')){
			deleteUser(obj);
		}
	});

	$(".modifyUser").on("click",function(){
		var obj = $(this);
		window.location.href=path+"/jsp/user.do?method=modify&uid="+ obj.attr("userid");
	});

});

其他管理模块

由于其他管理模块功能类似,我就不细说了直接贴图。功能类似,但是代码还是要一遍一遍的写,我写的时候都快不想写了。

值得讲的一个地方就是 删除模块小组 >> 话题>>评论

所以删除小组的时候 会把小组对应的话题删掉,也会把话题对应的评论删掉 由于三大范式 评论表中没有 小组的ID 所以这个实现比较麻烦

同理 删除话题也会删除话题对应的评论

    private void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet ===>删除小组中");

        String groupId= req.getParameter("groupid");

        System.out.println(groupId);

        Integer id=Integer.parseInt(groupId);

        GroupService groupService=new GroupServiceImpl();
        TopicService topicService=new TopicServiceImpl();
        CommentService commentService=new CommentServiceImpl();

        Boolean flag=groupService.delete(id);

        //获取小组下的话题列表
        List<Topic> topicList=topicService.getTopicList(id,"");
        System.out.println(topicList);

        //删除话题
        for(Topic topic:topicList){
            commentService.delete(0,topic.getId());
       }

        //删除小组下的话题
        Boolean flag2=topicService.delete(0,id);

        HashMap<String, String> resultMap = new HashMap<String, String>();

        if(flag==true){
            resultMap.put("delResult","true");
        }else{
            resultMap.put("delResult","false");
        }
        resp.setContentType("application/json");
        PrintWriter outPrintWriter = resp.getWriter();
        outPrintWriter.write(JSONArray.toJSONString(resultMap));
        outPrintWriter.flush();
        outPrintWriter.close();
    }

小组管理:

小组按照要求前台可以创建,但是我觉得这个小组是比较固定的,而且也是比较重要的,就像我们这个集训的赛道一样,所以我前台没有放创建小组的窗口,只有管理员在后台才能增删改查

image-20210821104804280

image-20210821104921233

image-20210821104931856

image-20210821104948437

image-20210821104958304

话题管理

话题和评论只能删除和查询 ,按理来说这两个也只能删除和查询

image-20210821105026008

总结

这次大作业也是花了很长时间,在集训的时候我因为提前组好了队伍出去社会实践了(考勤分估计没了),花了十几天的时间,只参加了前两天和最后几天的集训,少了很多时间学习。虽然之前自学过Java mysql 前端等等 但不怎么使用也差不多遗忘了。所以这20天我一遍学习一遍写项目,还是很充实的一个暑假,之后我也会慢慢完善我的第一个项目。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值