分类

课内:
不限
类型:
不限 毕业设计 课程设计 小学期 大作业
汇编语言 C语言 C++ JAVA C# JSP PYTHON PHP
数据结构与算法 操作系统 编译原理 数据库 计算机网络 软件工程 VC++程序设计
游戏 PC程序 APP 网站 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
年份:
不限 2018 2019

资源列表

  • 基于JSP实现的校园师生交流系统

    第1章 课设任务1.1 课程题目师生交流系统的设计与开发
    1.2 课设目的复习、巩固JavaWeb的基础知识,进一步加深对JavaWeb技术的理解和掌握;课程设计为学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机的结合起来,锻炼学生的分析解决实际问题的能力。培养学生在项目开发中团队合作精神、创新意识及能力
    1.3 开发环境
    操作系统:Windows
    开发工具:MyEclipse
    Java中间件服务器:Tomcat
    数据库: MySQL

    MyEclipse 是一个十分优秀的用于开发Java, J2EE的 Eclipse 插件集合,MyEclipse的功能非常强大,支持也十分广泛,尤其是对各种开源产品的支持十分不错。MyEclipse可以支持Java Servlet,AJAX,JSP,JSF,Struts,Spring,Hibernate,EJB3,JDBC数据库链接工具等多项功能。可以说MyEclipse是几乎囊括了目前所有主流开源产品的专属eclipse开发工具。
    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件。
    第2章 课设内容师生交流系统是一个教学系统,主要是帮助学生和教师更好进行交流,更好地将若干课程更加紧密地结合起来,更好地达到学以致用;达到教、学结合的目的;让学生能够更加完整而系统地掌握相关知识和技能。
    根据师生交流系统的基本需求,本系统需要完成以下任务:

    学生用户功能:学生登录之后可以对教学资料查询(可分页),教学视频播放和下载、试题下载
    教师用户功能:教师登录本系统可以上传教学资料、视频以及试题,另外可以对这些资料进行增删改查
    师生交流功能:学生可以向教师提问,教师可以对学生的提问进行答复
    管理用户功能:管理员登录系统之后可以分配学生和教师,对学生和教师进行管理

    第3章 需求分析从代码实现角度分析,该系统共包括以下几个部分:用户登录、信息的列表、信息的查询、信息的添加、信息的修改、信息的删除和退出登录。
    3.1系统用户角色分析用户分为学生用户、教师用户和管理员用户。
    学生登录之后可以对教学资料、教学视频、试题进行查询和下载,还可以对教学视频进行播放;教师用户登录后可以上传教学资料、教学视频和试题,还可以对这些资料进行增删改查;管理员用户登录后可以分配学生和教师,对学生和教师信息进行增删改查。在论坛功能中,所有用户都可以发表帖子和回复,只有管理员可以对帖子信息进行删改。
    3.2 功能需求分析3.2.1 用户登录功能描述:根据用户输入的用户名和密码,并选择用户角色(学生、教师或管理员)进行登录验证,输入正确则提示“成功”并进入系统主界面。输入错误则提示“失败”,并返回登录界面。
    功能约束:用户登录必须输入用户名、密码,并选择用户角色。登录成功后会根据用户权限的不同,显示具有不同功能的系统主界面。
    3.2.2 信息列表功能描述:在资料列表、视频列表、试题列表、学生管理、教师管理、论坛列表中,需要列出数据库中的数据。
    功能约束:需要按实际情况准确显示数据库表中的数据。
    3.2.3 信息查询功能描述:在列表的上方,通常要有输入框用于查询某一条或某几条特定信息,比如根据标题查找资料,根据用户名查找学生等。
    功能约束:查询时不需要输入全部信息,只需输入部分信息。
    3.2.4 信息添加功能描述:资料上传、视频上传、试题上传、用户添加、发表帖子、帖子回复等功能需要用到信息添加模块,添加时需按要求填写或选择信息,添加成功后会跳转到相应的列表界面。
    功能约束:添加信息时会自动获取当前时间并录入到数据表中,需要用到文件的上传。
    3.2.5 信息修改功能描述:管理员可以学生和教师进行编辑,还可以对帖子进行编辑,编辑成功会更新数据表中相应的信息,跳转到对应的列表。
    功能约束:修改时也会自动修改数据表中的时间为当前时间。
    3.2.6 信息删除功能描述:管理员和教师可以对资料、视频、试题进行删除,管理员可以对学生、教师的用户信息和帖子进行删除,删除成功会删除数据表中相应的信息并跳转到对应的列表。
    功能约束:删除数据会根据数据表的“id”进行删除。
    3.2.7 退出登录功能描述:当用户点击“退出”按钮时,会清空登录时保存的信息,并跳转到用户登录界面。
    3.3 相关技术简介3.3.1 前端技术在前端的开发设计上,使用了bootstrap和jquary进行辅助开发,提高了开发的效率。
    Bootstrap,来自 Twitter,是目前很受欢迎的前端框架。Bootstrap是基于 HTML、CSS、JavaScript的,它简洁灵活,使得Web开发更加快捷。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。国内一些移动开发者较为熟悉的框架,如WeX5前端开源框架等,也是基于Bootstrap源码进行性能优化而来。
    jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。
    3.3.2 后端技术本系统采用了SpringMVC框架进行后台的开发,大大加快了开发速度,使后台代码更加简洁与清晰,利于后期拓展与维护。
    Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。
    Spring MVC框架提供了一个DispatcherServlet作用前端控制器来分派请求,同时提供灵活的配置处理程序映射、视图解析、语言环境和主题解析,并支持文件上传。Spring MVC还包含了多种视图技术,例如JSP、Velocity、Tiles、iText和POI等。Spring MVC分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
    第4章 设计过程4.1 总体设计通过对用户需求和系统设计思想的分析,并根据界面展示需要,可以得出该系统可以分为六大模块:用户登录模块、教学资料模块、教学视频模块、试题资料模块、用户管理模块、论坛系统模块。
    4.1.1 系统功能模块设计经过分析,该系统要实现的是帮助学生和教师更好进行交流,达到辅助教学的目的。主要设计以下功能模块:
    用户登录模块
    用户在使用系统之前必须登录系统,登录时需要输入用户名、密码、验证码,选择用户角色进行登录。
    教学资料模块
    教学资料模块包括资料列表和资料上传两个部分,学生可以查看和下载资料,教师和管理员可以进行资料的增删改查。
    教学视频模块
    教学视频模块包括视频列表和视频上传两个部分,学生可以查看和下载视频,在线观看视频,教师和管理员可以进行视频的增删改查。
    试题资料模块
    试题资料模块包括试题列表和试题上传两个部分,学生可以查看和下载试题,教师和管理员可以进行试题的增删改查。
    用户管理模块
    管理员用户需要对学生用户和教师用户进行管理,包括学生列表、教师列表和用户添加三部分。用户添加功能需要首先选择角色,然后填写信息并提交。
    论坛系统模块
    论坛系统模块包括帖子列表和帖子发布两部分,所有用户都可以进行查看帖子列表和发表帖子,在帖子列表界面,点击帖子标题可以进入帖子详情,在帖子详情中用户可以查看回复内容及添加回复。
    4.1.2 用户登录模块结构图用户登录模块功能结构图,如图4.1所示:

    4.1.3 管理员用户功能结构图管理员用户功能结构图。如图4.2所示:

    4.1.4 学生用户功能结构图学生用户功能结构图,如图4.3所示:

    4.1.5 教师用户功能结构图教师用户功能结构图,如图4.4所示:

    4.2 详细设计4.2.1 系统主页面系统主页面分为三部分,分别是头部,左侧菜单栏和右侧主内容区,在之前的设计中大多使用iframe标签进行布局,但我从网上了解到这个设计有很大的弊端,比如:

    页面样式调试麻烦,出现多个滚动条
    浏览器的后退按钮失效
    过多会增加服务器的HTTP请求
    小型的移动设备无法完全显示框架
    产生多个页面,不易管理
    不容易打印
    代码复杂,无法被一些搜索引擎解读

    经过查阅资料,我了解到目前主流的应用都使用了ajax代替了iframe。把你本来想创建的iframe换成DIV。然后点击菜单的时候,调用ajax或者.load,调用后台,返回数据之后,直接填充到DIV里即可。
    部分实现代码如下:
    //左侧菜单代码<ul class="list-group" id="nav"> <li class="list-group-item li1" ><b>教学资料</b></li> <li class="list-group-item li" ><a target="data/list">资料列表</a></li> <li class="list-group-item li" ><a target="././data_upload">资料上传</a></li></ul>//AJAX部分代码$("#nav .li").click(function(){ var current = $(this); target = current.find('a').attr('target'); //找到a的链接 $(".li").removeClass("active1"); current.addClass("active1"); $.get(target,function(data){ $("#navContent").html(data); });});
    系统主界面如图4.5所示:

    4.2.2 基本功能实现用户登录模块

    功能描述:用户只有通过登录成功后才能进入系统,进行相应的操作。
    用户登录功能流程图,如图4.6所示


    //登录判断代码@RequestMapping(value="/login")public void login(String role,String username,String password,String rem,HttpServletRequest request,HttpServletResponse response) throws IOException{ User auser=null; auser=new User(); auser.setPassword(password); auser.setUsername(username); auser.setRole(role); boolean flag=userService.login(auser); PrintWriter out = response.getWriter(); if(flag){//记住我 if("true".equals(rem)){ System.out.println(URLEncoder.encode(username,"utf-8")); System.out.println(URLEncoder.encode(role,"utf-8")); Cookie cook =new Cookie("username",URLEncoder.encode(username,"utf-8")); cook.setMaxAge(14*24*60*60); //两个星期 response.addCookie(cook);Cookie cook1 =new Cookie("role",URLEncoder.encode(role,"utf-8")); cook1.setMaxAge(14*24*60*60); //两个星期 response.addCookie(cook1); } HttpSession session=request.getSession(); session.setAttribute("username", username); session.setAttribute("role", role); out.print("1");//返回登录信息 }else{ out.print("0"); } out.flush(); out.close();}
    用户登录界面如图4.7所示:

    教学资料模块
    教学资料模块包括资料列表和资料上传两个部分。

    功能描述:教师和管理员进行教学资料的增删改查,学生可以对教学资料进行查看和下载。
    //资料列表功能代码@RequestMapping(value="/list") public ModelAndView list(Integer currPage,String soukey){ ModelAndView mv=new ModelAndView(); String key="%%"; if(soukey!=null){ key="%"+soukey+"%"; } int pageSize=5; if(currPage==null||currPage==0){ currPage=1; } int index=(currPage-1)*pageSize; int totalCount=Integer.parseInt(dataService.findCount(key).get(0).get("count(id)").toString()); Page page=new Page(); page.setPageSize(pageSize); page.setTotalCount(totalCount); page.setCurrPage(currPage); mv.addObject("page", page); List<Map<String,Object>> list=dataService.findAll(index,pageSize,key); mv.addObject("list", list); mv.addObject("key",soukey); mv.setViewName("list"); return mv; }
    资料列表界面如图4.8所示:

    资料上传界面如图4.9所示:

    教学视频模块
    教学视频模块分为视频列表和视频上传两部分。

    功能描述:教师和管理员可以进行教学视频的增删改查,学生用户可以在线播放视频和下载视频。
    //视频上传功能代码@RequestMapping(value="/upload")public ModelAndView upload(HttpServletRequest request,HttpServletResponse response) throws IOException{multipartRequest=(MultipartHttpServletRequest)request; String title=""; String path=""; String author=""; String fname=""; response.setContentType("text/html;charset=utf-8"); try { //1.创建DiskFileItemFactory工厂对象 DiskFileItemFactory factory=new DiskFileItemFactory(); File f=new File("E:\\temp"); if(!f.exists()) { f.mkdirs(); } //2.创建ServletFileUpload对象 ServletFileUpload fileupload=new ServletFileUpload(factory); fileupload.setHeaderEncoding("utf-8"); //3.解析request,得到上传文件的FileItem对象 List<FileItem> fileitems=fileupload.parseRequest(request); //获取字符流 PrintWriter writer=response.getWriter(); //遍历集合 for(FileItem fileitem:fileitems){ //判断是否为普通字段 if(fileitem.isFormField()){ //获得字段名和字段值 String name=fileitem.getFieldName(); if(name.equals("name")) { //如果name不为空,将其保存在value中 if(!fileitem.getString().equals("")) { String value=fileitem.getString("utf-8"); writer.print("上传者:"+value+"<br/>"); author=value; } } }else{ //获取上传文件名 String filename=fileitem.getName(); //数据表标题 title=filename; //处理上传文件 if(filename!=null&&!filename.equals("")){ writer.print("上传的文件名称是:"+filename+"<br/>"); //截取出文件名 filename=filename.substring(filename.lastIndexOf("\\")+1); //文件名需要唯一 filename=UUID.randomUUID().toString()+"_"+filename; fname=filename; //在服务器上创建同名文件 String webPath="/upload/"; //组合成完整的服务器路径 String filepath=request.getServletContext().getRealPath(webPath+filename); path=filepath; //创建文件 File file=new File(filepath); file.getParentFile().mkdirs(); file.createNewFile(); //获得上传文件流 InputStream in=fileitem.getInputStream(); //使用FileOutputStream打开服务器端的上传文件 FileOutputStream out=new FileOutputStream(file); //流的对拷 byte[] buffer=new byte[1024];//每次读取一个字节 int len; //上传文件的字节输出到服务器的上传文件输出流中 while((len=in.read(buffer))>0){ out.write(buffer,0,len); } //关闭流 in.close(); out.close(); //删除临时文件 fileitem.delete(); writer.print("上传成功!<br/>"); } } } } catch (FileUploadException e) { e.printStackTrace(); } Video video=new Video(); video.setTitle(title); video.setAuthor(author); video.setPath("upload\\"+fname); System.out.println(fname); video.setTime(new Date()); videoService.add(video); return list(1,null); }
    视频列表界面如图4.10所示:

    视频上传界面如图4.11所示:

    视频在线播放界面如图4.12所示:

    试题资料模块
    试题资料模块包括试题列表和试题上传两部分。

    功能描述:教师和管理员用户可以对试题进行增删改查,学生用户可以对试题进行查看和下载。
    //试题下载功能代码@RequestMapping(value=("/download"))public void download(HttpServletRequest request,HttpServletResponse response) throws IOException{ /* * 获取下载地址,下载 */ //获取相对路径 String filename = request.getParameter("path"); //获取要下载的文件的物理路径 String filepath = request.getServletContext().getRealPath("/")+filename; int index = filename.lastIndexOf("/"); if(index!=-1) filename = filename.substring(index+1);//获取文件名 // 为了使下载框中显示中文文件名称不出乱码! String framename = filenameEncoding(filename, request); String contentType = request.getServletContext() .getMimeType(filename);//通过文件名称获取MIME类型 String contentDisposition = "attachment;filename=" + framename;//为了显示下载框 // 输入流 FileInputStream input = new FileInputStream(filepath); //设置头 response.setHeader("Content-Type", contentType); response.setHeader("Content-Disposition", contentDisposition); // 获取绑定了响应端的流(输出流) ServletOutputStream output = response.getOutputStream(); IOUtils.copy(input, output);//把输入流中的数据写入到输出流中。 input.close();}
    试题列表界面,如图4.13所示:

    试题上传界面,如图4.14所示:

    用户管理模块
    学生和教师用户的账号需要由管理员用户来添加和分配,用户管理模块主要包括学生管理、教师管理和用户添加三部分。

    功能描述:管理员用户可以对学生和教师用户的用户信息进行增删改查。
    //用户信息添加和编辑代码 @RequestMapping(value="/edit")public ModelAndView edit(String id,String role,String username,String password,String sex,String email,String phone,String birthday) throws ParseException{ ModelAndView mv=new ModelAndView(); User auser=new User(); auser.setRole(role); auser.setUsername(username); auser.setPassword(password); auser.setSex(sex); auser.setEmail(email); auser.setPhone(phone); SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); Date date = formatter.parse(birthday); auser.setBirthady(date); if(id==null||"".equals(id)){ userService.addUser(auser); }else{ auser.setId(Integer.parseInt(id)); userService.editUser(auser); } return list(role,1,null);}
    学生用户管理界面,如图4.15所示:

    教师用户管理界面,如图4.16所示:

    用户添加界面,如图4.17所示:

    论坛系统模块
    论坛系统包括论坛列表和发表帖子两部分。

    功能描述:所有用户都可以进行帖子的发表、浏览和回复,管理员用户可以对帖子内容进行增删改查。
    //帖子回复功能代码@RequestMapping(value="/replyAdd")public ModelAndView replyAdd(String forumid,String author,String lou,String content){ //敏感词过滤 content=KeyWordFilter.keyWordFilter(content); Reply areply=new Reply(); areply.setForumid(Integer.parseInt(forumid)); areply.setAuthor(author); areply.setContent(content); areply.setTime(new Date()); areply.setLou(Integer.parseInt(lou)); forumService.replyAdd(areply); return show(forumid,1);}
    论坛列表界面,如图4.18所示:

    论坛发帖界面,如图4.19所示:

    帖子详情界面,如图4.20所示:

    4.2.3 系统优势与特色保存登录功能

    功能描述:用户在进行登录时,如果选中“记住我”复选框,系统会将用户信息保存到浏览器cookie中,保存时间为两周,在cookie生效时,用户进入系统时无需再次登录便可直接进入系统,极大地提升了用户体验,提高工作的效率。
    //保存用户信息到cookie中if("true".equals(rem)){ Cookie cook =new Cookie("username",URLEncoder.encode(username,"utf-8")); cook.setMaxAge(14*24*60*60); //两个星期 response.addCookie(cook); Cookie cook1 =new Cookie("role",URLEncoder.encode(role,"utf-8")); cook1.setMaxAge(14*24*60*60); //两个星期 response.addCookie(cook1);}//从cookie中读取用户信息Cookie cookies[] =request.getCookies();if(cookies!=null){ for(int i=0;i<cookies.length;i++){ if(cookies[i].getName().equals("username")){ String username=cookies[i].getValue(); session.setAttribute("username", URLDecoder.decode(username, "utf-8")); } if(cookies[i].getName().equals("role")){ String role=cookies[i].getValue(); session.setAttribute("role", URLDecoder.decode(role, "utf-8")); } }}
    用户登录界面如下:

    AJAX动态验证功能

    功能描述:本系统使用AJAX技术进行用户名密码的验证,验证码的验证和用户添加时的用户名查重。实现了页面无刷新,在页面内与服务器通信,给用户的体验非常好。使用异步方式与服务器通信,不需要打断用户的操作,具有更加迅速的响应能力。减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
    //用户登录功能AJAX代码$.ajax({ url:"user/login", data:{role:$("#role").val(),username:$("#username").val(),password:$("#password").val(),rem:$("#rem").is(':checked')}, dataType: 'text', type: 'post', scriptCharset: 'utf-8', success:function(result){ if(eval("("+result+")")=="0"){ $("#unerr").removeClass("text-success"); $("#unerr").addClass("text-danger"); $("#unerr").text("用户名或密码错误"); $("#username").focus(); }else if(eval("("+result+")")=="1"){ window.location.href = "user/success"; } }});
    用户名密码验证和验证码验证界面如图4.22所示:

    第5章 调试过程5.1 遇到的问题
    登录时输入错误,并不会提示登录失败,而是网页直接报错
    提交表单时出现乱码
    rs.next()不能正确获取数据库中的数据
    不知道什么时候使用post提交,什么时候使用get提交。

    5.2 解决方法
    登录判断页面(login_do.jsp)中,登录信息session的保存没有放在判断是否为空的判断语句(if(list!=null))中,导致登录失败也会保存session,这时就无法正确获取登录信息,导致网页报错。将session放在判断语句中就可以解决
    表单提交时以get的请求发送到tomcat服务器后又会以默认的(ISO8859-1)解码,这时会出现中文乱码,改为post提交方式就解决了
    ResultSet是一个结果集,即ResultSet存有一个表(通过执行查询数据库的语句生成),该表的当前行可以访问(当前行的初始位置是null),可以使用rs.next()方法移动到下一行(即表的第一行),如果新的当前行有效(即有值)就返回true,然后就可以使用get方法获取该行各列的值了,如果不存在下一行,则返回 false;因为这个方法会抛出一个SQLException,故要捕捉(try-catch)。直接使用rs.next()不能获取,前面要加上判断语句(if(rs.next)或while(rs.next))
    get方法传输数据会在地址栏显示,并且数据不能过长,但会优先读取本地缓存,很多时候会加速用户访问。一般获取数据用get,进行数据更改用post。

    第6章 系统测试以下测试均以管理员身份进行登录,测试师生交流系统的各项功能。
    6.1 用户登录模块用户登录输入管理员用户密码,选择管理员角色,如图6.1所示:

    点击登录按钮,跳转进入系统主界面,如图6.2所示:

    由上图可知,用户登录功能运行成功。
    6.2 系统功能模块对教学资料、教学视频、试题资料、用户资料、论坛帖子的增删改查和资料下载功能较为类似,这里以教学资料为例进行测试。
    资料列表功能测试
    点击左侧菜单“教学资料”,再点击“资料列表”,进入资料列表界面。资料列表界面如图6.3所示:

    点击右侧“下载”,可以进行资料的下载,如图6.4所示。

    资料上传功能测试
    点击左侧菜单中的“资料上传”,进入资料上传界面,输入作者信息,选择资料文件,如图6.5所示:

    点击“提交”按钮,提示“成功”,跳转进入资料列表界面,可以看到刚添加的信息,如图6.6所示:

    查询资料功能测试
    进入资料列表,在上方的查询框中输入标题的关键字,如图6.7所示:

    点击“搜索”按钮,后台查询并显示要查询的信息,如图6.8所示:

    教学资料的删除功能测试
    这里进行批量删除功能的测试,进入资料列表,选中需要删除的资料,如下图所示:

    点击“批量删除”按钮,成功删除指定信息,并自动刷新界面,如图6.10所示:

    教学视频播放测试
    点击左侧“视频列表”菜单,点击标题或右侧的“播放”,即可进入播放界面,如图6.11所示:

    论坛系统测试
    点击右侧“论坛系统”菜单,再点击“论坛”,进入论坛列表界面,如图6.12所示:

    点击标题,进入帖子详情界面,如图6.13所示:

    在下方的回复栏中可以进行帖子回复,如图6.14所示:

    帖子发表功能测试
    点击右侧“发表帖子”菜单,进入发表帖子页面,填写信息,如图6.14所示:

    点击“提交”按钮,帖子成功发表,并转到论坛列表界面,如图6.15所示:

    第7章 课设小结经过这段时间的课设学习,我收获了很多。在自己的努力和老师的耐心指导下,终于完成了这次课设的内容。这其中的酸甜苦辣只有经历过才体会得到,曾无数次找错误找到崩溃,无数次想代码想到忘记吃饭,这一刻才体会到收获的喜悦,这是发自内心的。
    同时在这次课设中,我培养了独立思考、动手操作的能力,在各种其它能力上也都有了提高。我学会了很多学习的方法。而这是日后最实用的。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。这对于我的将来也有很大的帮助。以后,不管有多苦,我想我都能变苦为乐,找寻有趣的事情,发现其中珍贵的事情。以后遇到困难的问题,我除了苦恼,更多的是欣喜,因为解决了它我就能成长。
    我明白了自己知识还比较欠缺,只是学习书本知识还是远远不够的,自己不会的东西还有太多,学习需要自己长期的积累,在以后的学习、工作中都应该不断的学习,将课本的理论知识与生活中的实践知识相结合,不断提高自己文化知识和实践能力。
    第8章 参考文献[1] 张娜. JavaWeb开发技术教程(第二版).清华大学出版社,2018.1
    [2] 王珊,萨师煊.数据库系统概论(第5版).高等教育出版社,2017.3
    [3] Cay S. Horstmann / Gary Cornell. JAVA核心技术(卷1) 机械工业出版社,2008
    [4] [美] Bruce Eckel. Java编程思想 [第4版] 机械工业出版社,2007
    1 评论 39 下载 2019-02-19 18:16:30 下载需要14点积分
  • 基于Android Studio实现的2048游戏

    1 需求分析1.1 背景与意义1.1.1 手机应用市场发展现状随着4G越来越普及以及手机应用的日益丰富还有智能水平的不断提高,从便携性和随身性这两方面来考虑,电脑所带来的体验已经不能跟手机相提并论了,它已经完美的超越了电脑。
    现如今Android、苹果等各智能手机已经基本占领整个手机市场,从而使得更多应用的出现,而手机游戏应用在其中占领主要位置。
    随着Android智能手机的普及以及游戏种类的多元化,使得Android手机游戏用户规模保持着稳步增长之势。
    1.1.2 国内外现状目前国内外的Android开发还是主要以应用开发为主,主要分成三类:企业应用、通用应用及游戏应用。企业应用的开发主要是一些大公司为了自己的品牌而开发的;通用应用主要是一些创业型公司或者独立开发者为了自己盈利开发的应用;游戏应用目前和通用应用相同。
    2048小游戏是一款最近风靡全球的手机游戏,简单的游戏模式和趣味的玩法,几乎游戏下载排行榜的前20名都可以看到“它的身影”。
    1.1.3 此游戏的意义现如今,手机游戏已在我们的生活中占据一席之地,并在一步步的壮大。可以说,随着它的迅猛发展,现今的手机游戏已经不单单是一种缓解压力的工具,而是形成了一种文化现象。随着游戏软件在市场的一步步壮大,与其有关的文化也随之传播。
    2048游戏的制作属于电子游戏中益智类小游戏,它做到了娱乐性、趣味性、教育性相统一。益智类的游戏即是需要去开动大脑思考从而获得游戏的胜利。简单的益智类游戏可以使玩家在娱乐中不断地开发大脑。这样一来就实现了在娱乐中学习。
    1.2 系统需求分析1.2.1 系统功能需求分析系统主要实现以下的几个功能:呈现游戏界面、重新开始游戏、当前分数和最高分数、游戏帮助等功能。
    重新开始游戏是当玩家无法满足当前进度时点击此按钮就会重新开始游戏,如果玩家处于不同关卡时提示重新开始游戏还是停留在此关卡。游戏帮助是当新手玩此游戏时无法知道游戏玩法时给予相应的提示。呈现游戏界面是游戏开始时主界面在游戏区域会生成4x4的矩阵同时在矩阵里面随机生成两个2或4的游戏卡片。当前分数和最高分数是显示此局玩家所获得的分数和历史上最高的分数,如果当前的分数超过最高的分数,那么最高分数显示当前的分数。如下图所示:

    1.2.2 游戏的基本规则在开始游戏后玩家通过滑动屏幕来操控卡片的移动方向,当卡片滑动中如果有两张卡片相同且他们中间也没有其他卡片时,在滑动的过程中这两张卡片会合并,显示为这两张卡片之和。在滑动过程中有三张卡片相同时只会合并向滑动方向两张卡片。在滑动中如果有两张卡片一样同时又有一张卡片的值跟这两张卡片相加的值时,滑动只会使那两张相同的卡片合并而不会接着让合并后的卡片和另一张卡片合并。
    2 系统分析与设计2.1 系统流程设计游戏进入开始页面,能够进入游戏的主界面并开始普通开局,从主界面能够重新开始游戏、查看帮助和进入关卡选择界面。当玩家点击重新开始按钮会弹出相应的对话框让玩家选择,如果玩家选择“是”时则重新开始游戏,如果选择“否”则返回游戏界面不做任何处理。在开始界面按返回按钮时则会退出游戏。
    游戏流程如下图所示:

    2.2 系统模块设计从总体出发,将该系统划分为三大模块:“菜单设计”、“界面设计”和“算法设计”。
    2.2.1 菜单设计菜单的实现是在游戏界面,可进一步划分为三个模块,分别是:“重新开始”、“退出游戏”、“游戏帮助”,如图所示:

    2.2.2 界面设计


    开始界面
    游戏界面









    2.2.3 算法设计当有两张卡片相同时,向它们可以碰撞的方向滑屏,卡片会移动到最底边并生成其两倍数字的卡片,并且生成一个“2”或者“4”的卡片。如图所示:



    生成2
    生成4









    当有两张卡片相同时,且在它们相同的方向有张跟他们之和的卡片,向它们可以碰撞的方向滑屏,相同的卡片会移动到无法移动的位置并生成其两倍数字的卡片,但合成的方向不会跟那两张数字的卡片合并,并且生成一个“2”或者“4”的卡片。如图所示:



    生成2
    生成4









    当界面上没有空位并且两两相邻的卡片不相同时游戏结束。如图所示:

    2.3 本章小结本章主要对游戏所实现的功能进行需求分析,分析了图形的特点和实现的可行性。对系统的性能进行了详细的分析。对系统的流程,系统所需的图形文件,系统的总体架构和系统用例进行了设计。通过本章的分析、设计能更加具体的了解系统功能,对系统所要实现的功能和图形文件有了更深的认识。为下一章系统功能的具体实现提供了可靠的参考依据。
    3 系统实现3.1 开始界面的实现游戏的主界面是按钮,只是为了实现界面的跳转,当玩家点击开始游戏就会调用loginActivity.java,此函数让页面跳转到游戏界面开始游戏,代码及图片如下所示:
    public class loginActivity extends MainActivity { protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.login); }}

    3.2 游戏界面的实现游戏界面主要是在activity_main.xml中当前分数、最高分数、重新开始按钮、退出游戏按钮、游戏帮助按钮、帮助按钮,当跳转到游戏界面时就会调用并执行MainActivity.java函数来展示游戏界面,代码及图片如下所示:
    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);}

    3.3 游戏滑动卡片移动的实现当玩家滑动屏幕时,主要通过GameView函数来监听玩家手指滑动的位置,先通过获取开始坐标和结束坐标,然后通过比较结束坐标跟开始坐标的差值来判断玩家是怎么滑动屏幕的。判断出玩家的滑动轨迹后,通过调用swipeLeft、swipeRight、swipeUp、swipeDown方法来实现卡片的移动,代码及图片如下所示:
    private void initGameView(){ setColumnCount(4); //将面板设置成4列 setBackgroundColor(0xffbbada0); System.out.println("initGameView"); setOnTouchListener(new View.OnTouchListener() { /* * startX:手机刚开始在屏幕上的X坐标 * startY:手机刚开始在屏幕上的Y坐标 * offsetX,offsetY,分别是手指在屏幕上的X,Y上的偏移量 */ private float startX,startY,offsetX,offsetY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: startX = event.getX(); startY = event.getY(); break; case MotionEvent.ACTION_UP: offsetX = event.getX() - startX; offsetY = event.getY() - startY; if(Math.abs(offsetX) > Math.abs(offsetY)){ if(offsetX < -5){ swipeLeft(); System.out.println("Left"); }else if(offsetX > 5){ swipeRight(); System.out.println("Right"); } } else{ if(offsetY < -5){ swipeUp(); System.out.println("Up"); }else if(offsetY > 5){ swipeDown(); System.out.println("Down"); } } break; } return true; } });}//向左滑动public void swipeLeft(){ boolean meger = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x+1; x1 < 4; x1++) { if(cardsMap[x1][y].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); x--; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger = true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向右滑动public void swipeRight(){ boolean meger = false; for (int y = 0; y < 4; y++) { for (int x = 3; x >=0; x--) { for (int x1 = x-1; x1 >= 0; x1--) { if(cardsMap[x1][y].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); x++; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; }break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向上滑动public void swipeUp(){ boolean meger = false; for (int x= 0; x< 4; x++) { for (int y = 0; y < 4; y++) { for (int y1 = y+1; y1 < 4; y1++) { if(cardsMap[x][y1].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); y--; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}//向下滑动public void swipeDown(){ boolean meger = false; for (int x = 0; x< 4; x++) { for (int y = 3; y>= 0;y--) { for (int y1 = y-1; y1 >=0; y1--) { if(cardsMap[x][y1].getNum()>0){ if(cardsMap[x][y].getNum()<=0){ /* * 将下标为(x,y)所在位置的卡片上的数字 * 设置为,坐标为(x1,y)所在位置的卡片上的值; * 第二步,将坐标(x1,y)所在位置的卡片上的数字 * 设置为0 * (即:变成空卡片) */ cardsMap[x][y].setNum( cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); y++; meger =true; break; }else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); MainActivity.getMainActivity(). addScore(cardsMap[x][y].getNum()); meger =true; } break; } } } } if(meger){ addRandomNum(); checkComplete(); }}



    效果1
    效果2









    3.4 重新开始游戏功能的实现当玩家点击游戏界面的重新开始游戏时,会弹出给玩家选择的对话框,让玩家选择“是”时游戏会重新开始,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog3 = new AlertDialog.Builder(this); dialog3.setTitle("提示:"); dialog3.setMessage("你确定重新开始吗?"); dialog3.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog3.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog3.show(); }

    3.5 退出游戏功能的实现当玩家中途有事想退出游戏时会弹出给玩家选择的对话框,让玩家选择“是”时游戏会退出,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle("提示:"); dialog.setMessage("你确定要离开吗?"); dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { System.exit(0); } }); dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show(); }

    3.6 游戏帮助功能的实现当新玩家进入到游戏且不知道此游戏玩法时,玩家可以点击游戏帮助按钮来了解游戏玩法,点击按钮时游戏会弹出对话框显示游戏玩法,代码及图片如下所示:
    public void onClick(View view){ AlertDialog.Builder dialog2 = new AlertDialog.Builder(this); dialog2.setTitle("hey,guy!"); dialog2.setMessage("这么简单的游戏你确定需要帮助?"); dialog2.setNegativeButton("继续玩~", new DialogInterface.OnClickListener({ @Override public void onClick(DialogInterface dialog, int which) { } }); dialog2.show();}

    3.7 本章小结本章主要阐述本游戏相关功能的实现,详细的讲述了主界面的实现和各按钮功能的实现。
    4 测试本章主要对系统的功能进行测试,此次测试只是进行简单的调试,来确定游戏的各项功能是否能够正常运行。
    4.1 游戏流程测试该测试主要验证游戏能否实现场景的切换,当界面在开始界面时只显示按钮画面,当玩家点击此界面的开始按钮时跳转到游戏界面,如图所示:



    效果1
    效果2









    4.2 游戏模式该测试主要是测试游戏能否正常运行,当玩家滑动屏幕时能否正常的移动和当卡片相同时是否能够相加,还有就是测试游戏是否能正常结束。



    效果1
    效果2









    4.3 本章小结本章是对游戏系统进行简单的测试,通过测试可以看出此游戏可以正常的工作,同时一些功能也能够实现。
    5 总结本次课程设计的内容大部分都是参照课堂所讲以及一些网站给出的各种建议写的,在写的过程中遇到了很多问题,学到了很多东西。期间大概是因为基础不够好,只是找错误就花了很长时间。不过正因为这些错误,才能学到更多的知识,才能把知识点掌握的更牢靠,对于一些没有实现的功能,之后我一定会多花费些时间研究出来。我的课程设计优化的空间还相当大,希望老师能给出指导!
    3 评论 90 下载 2018-12-20 18:49:18 下载需要8点积分
  • 基于JAVA实现的支持多线程访问的WEB服务器

    1.系统概述1.1 业务背景web服务提供了可供浏览的网页,对浏览web服务的需求是本程序的背景,当然现在已经有很多web服务器的很好的实现,本程序也不可能说做得比知名的那些要好,在这里程序的目的是为了锻炼网络程序设计与实践和软件系统设计与开发实践能力。
    1.2 总体目标实现一个web服务器,能够提供让标准浏览器用HTTP协议来进行访问的网页,并且能够支持多线程非阻塞的服务,最后会提供一个web服务器程序。
    2.系统分析和设计2.1 系统概述2.1.1 业务需求描述
    为标准浏览器提供web服务
    能够接受http请求并返回html网页
    能够支持多线程非阻塞的访问

    2.1.2 外部接口需求
    硬件接口:无直接硬件接口,只通过OS等软件接口与硬件间接交互
    软件接口:相应的JDK、JVM环境,以及标准的浏览器软件
    通讯接口: HTTP协议

    2.1.3 非功能性需求
    Web服务器要求响应时间要短
    安全可靠

    2.1.4 约束条件开发环境

    Eclipse-Java IDE,windows7系统
    整个项目由Java开发,所以要求系统装有相应的JDK、JVM环境,另外,web服务器要求系统有http协议的接口,web客户端即为标准的浏览器软件

    开发规范

    文件命能清楚的描述其功能
    代码中的空格与空行上下保持一致
    有适量且清楚的注释
    界面整洁,方便使用
    所有函数及变量有能描述其功能的名字
    应注意代码的简洁和优化

    2.2 用例模型2.2.1 用例图
    2.2.2 详细描述


    用例名称
    Web浏览器查看网页




    描述
    用户用Web浏览器访问Web服务器的一个网页:http://localhost:6789/13S103066.html


    参与者与关注点
    Web浏览器(用户):希望得到快速的响应,能够看到正确的网页。Web服务器:希望能够快速正确地完成浏览器请求,并且能够处理多用户同时访问的场景。


    事件流
    主成功场景(或基本流程): 用户在浏览器中输入要访问的网址:http://localhost:6789/13S103066.html; web服务器解析HTTP协议请求; web服务器处理该请求并通过TCP连接向浏览器返回目标网页html文件;浏览器解析并显示该html文件;用户看到该网页;完成。 扩展(或替代流程): 传递网页的TCP连接建立失败:web服务器报错给服务器管理员,管理员检查服务器状态是否异常;Web服务器没有响应(浏览器无法连接到服务器):检查web服务器是否已经运行、网址是否输入正确。


    前置条件
    Web浏览器已运行



    2.3 领域类图2.3.1 Web(TCP)类图
    2.3.2 Web(TCP)核心顺序图
    2.4 体系结构设计
    2.5 程序流程图
    2.6 测试截图
    3.总结综上所述,程序实现了一个支持多线程访问的Web服务器。在简单规模的测试及使用下,程序运行正确且良好,在较大用户数下表现得一般,响应时间不是很好。作为一个学习网络程序设计的程序已经完成了目标。
    这次作业中,复习了很多计算机网络的相关知识的同时也学到了很多新的实践方面的知识,锻炼了编程能力,感谢老师的辛勤付出。
    1 评论 1 下载 2019-05-06 11:45:36 下载需要12点积分
  • 基于Python的信息检索课程设计

    sdu视点新闻全站爬虫爬取+索引构建+搜索引擎查询练习程序

    爬虫功能使用Python的scrapy库实现,并用MongoDB数据库进行存储。
    索引构建和搜索功能用Python的Whoosh和jieba库实现。(由于lucene是java库,所以pyLucene库的安装极其麻烦,因此选用Python原生库Whoosh实现,并使用jieba进行中文分词。)
    搜索网页界面用django实现,页面模板套用BootCDN。

    1 要求以下是检索的基本要求:可以利用lucene、nutch等开源工具,利用Python、Java等编程语言,但需要分别演示并说明原理。
    1.1 Web网页信息抽取以山东大学新闻网为起点进行网页的循环爬取,保持爬虫在view.sdu.edu.cn之内(即只爬取这个站点的网页),爬取的网页数量越多越好。
    1.2 索引构建对上一步爬取到的网页进行结构化预处理,包括基于模板的信息抽取、分字段解析、分词、构建索引等。
    1.3 检索排序对上一步构建的索引库进行查询,对于给定的查询,给出检索结果,明白排序的原理及方法。
    2 运行方式
    运行sduspider/run.py来进行网络爬虫,这个过程将持续十多个小时,但可以随时终止,在下次运行时继续。
    运行indexbuilder/index_builder.py来对数据库中的72000条数据构建索引,该过程将持续几个小时,但可以随时终止。
    如果不熟悉Whoosh库的构建索引和query搜索功能,可以参考运行indexbuilder/sample.py。
    运行indexbuilder/query.py来测试搜索功能。
    运行searchengine/run_server.py打开搜索网页服务器,在浏览器中打开127.0.0.1:8000进入搜索页面执行搜索。

    3 所需python库
    scrapy
    requests
    pymongo
    whoosh
    jieba
    django

    4 所需数据库
    MongoDB
    Mongo Management Studio 可视化工具(可选)

    5 爬虫特性爬虫代码位于sduspider/目录下。
    5.1 爬取内容爬虫爬取以 http://www.view.sdu.edu.cn/info/ 打头的所有新闻页面的内容,这些内容包括:



    Item
    Item name




    标题
    newsTitle


    链接
    newsUrl


    阅读量
    newsCliek


    发布时间
    newsPublishTime


    文章内容
    newsContent



    # spider.py# 爬取当前网页 print('start parse : ' + response.url) self.destination_list.remove(response.url) if response.url.startswith("http://www.view.sdu.edu.cn/info/"): item = NewsItem() for box in response.xpath('//div[@class="new_show clearfix"]/div[@class="le"]'): # article title item['newsTitle'] = box.xpath('.//div[@class="news_tit"]/h3/text()').extract()[0].strip() # article url item['newsUrl'] = response.url item['newsUrlMd5'] = self.md5(response.url) # article click time item['newsClick'] = box.xpath('.//div[@class="news_tit"]/p/span/script/text()').extract()[0].strip() pattern = re.compile(r'\(.*?\)') parameters = re.search(pattern, item['newsClick']).group(0) parameters = parameters[1:-1].split(',') parameters[0] = re.search(re.compile(r'\".*?\"'), parameters[0]).group(0)[1:-1] parameters[1] = parameters[1].strip() parameters[2] = parameters[2].strip() request_url = 'http://www.view.sdu.edu.cn/system/resource/code/news/click/dynclicks.jsp' request_data = {'clicktype': parameters[0], 'owner': parameters[1], 'clickid': parameters[2]} request_get = requests.get(request_url, params=request_data) item['newsClick'] = request_get.text # article publish time item['newsPublishTime'] = box.xpath('.//div[@class="news_tit"]/p[not(@style)]/text()').extract()[0].strip()[5:] # article content item['newsContent'] = box.xpath('.//div[@class="news_content"]').extract()[0].strip() regexp = re.compile(r'<[^>]+>', re.S) item['newsContent'] = regexp.sub('',item['newsContent']) # delete templates <> # 索引构建flag item['indexed'] = 'False' # yield it yield item
    5.2 宽度优先搜索爬取爬虫基于宽度优先搜索,对http://www.view.sdu.edu.cn/区段的网址进行爬取,并将http://www.view.sdu.edu.cn/info/区段的新闻内容提取出来。
    # settings.py# 先进先出,广度优先DEPTH_PRIORITY = 1SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'
    5.3 二分法去重所有已经爬取过的网址都会以MD5特征的形式顺序存储在list中,当获取新的url时,通过二分法查找list中是否存在该url的特征值,以达到去重的目的。
    Scrapy库自带了查重去重的功能,但为了保证效率,自行编写了二分法去重,但并未关闭scrapy库自带的去重功能。
    # spider.py# md5 checkmd5_url = self.md5(real_url)if self.binary_md5_url_search(md5_url) > -1: # 二分法查找存在当前MD5 passelse: self.binary_md5_url_insert(md5_url) # 二分法插入当前MD5 self.destination_list.append(real_url) # 插入爬虫等待序列 yield scrapy.Request(real_url, callback=self.parse, errback=self.errback_httpbin)
    5.4 断点续爬每爬取一定次数后都会将当前爬虫状态存储在pause文件夹下,重新运行爬虫时会继续上一次保存的断点进行爬取。Scrapy有自带的断点续爬功能(在settings.py中设置),但貌似在Pycharm中行不通。
    # spider.py# counter++,并在合适的时候保存断点def counter_plus(self): print('待爬取网址数:' + (str)(len(self.destination_list))) # 断点续爬功能之保存断点 if self.counter % self.save_frequency == 0: # 爬虫经过save_frequency次爬取后 print('Rayiooo:正在保存爬虫断点....') f = open('./pause/response.seen', 'wb') pickle.dump(self.url_md5_seen, f) f.close() f = open('./pause/response.dest', 'wb') pickle.dump(self.destination_list, f) f.close() self.counter = self.save_frequency self.counter += 1 # 计数器+1
    5.5 数据存入MongoDB关系类数据库不适用于爬虫数据存储,因此使用非关系类数据库MongoDB。数据库可以用可视化工具方便查看,例如Mongo Management Studio。
    # pipelines.pyclass MongoDBPipeline(object): def __init__(self): host = settings["MONGODB_HOST"] port = settings["MONGODB_PORT"] dbname = settings["MONGODB_DBNAME"] sheetname = settings["MONGODB_SHEETNAME"] # 创建MONGODB数据库链接 client = pymongo.MongoClient(host=host, port=port) # 指定数据库 mydb = client[dbname] # 存放数据的数据库表名 self.post = mydb[sheetname] def process_item(self, item, spider): data = dict(item) # self.post.insert(data) # 直接插入的方式有可能导致数据重复 # 更新数据库中的数据,如果upsert为Ture,那么当没有找到指定的数据时就直接插入,反之不执行插入 self.post.update({'newsUrlMd5': item['newsUrlMd5']}, data, upsert=True) return item

    6 索引构建特性索引构建代码位于indexbuilder/目录下。
    6.1 断点续构构建倒排索引的过程比较缓慢,每小时只能构建10000条新闻的索引,因此在索引构建时及时存储新构建的索引,以保证能够断点续构。
    6.2 中文分词Whoosh自带的Analyzer分词仅针对英文文章,而不适用于中文。从jieba库中引用的ChineseAnalyzer保证了能够对Documents进行中文分词。同样,ChineseAnalyzer在search时也能够对中文查询query提取关键字并进行搜索。
    # index_builder.pyfrom jieba.analyse import ChineseAnalyzeranalyzer = ChineseAnalyzer()# 创建索引模板schema = Schema( newsId=ID(stored=True), newsTitle=TEXT(stored=True, analyzer=analyzer), newsUrl=ID(stored=True), newsClick=NUMERIC(stored=True, sortable=True), newsPublishTime=TEXT(stored=True), newsContent=TEXT(stored=False, analyzer=analyzer), # 文章内容太长了,不存)
    6.3 Query类提供搜索APIQuery类自动执行了从index索引文件夹中取倒排索引来执行搜索,并返回一个结果数组。
    # query.pyif __name__ == '__main__': q = Query() q.standard_search('软件园校区')
    7 搜索引擎特性搜索引擎代码位于searchengine/目录下。
    7.1 Django搭建Web界面Django适合Web快速开发。result页面继承了main页面,搜索结果可以按照result中的指示显示在页面中。在django模板继承下,改变main.html中的页面布局,result.html的布局也会相应改变而不必使用Ctrl+c、Ctrl+v的方式改变。
    # view.pydef search(request): res = None if 'q' in request.GET and request.GET['q']: res = q.standard_search(request.GET['q']) # 获取搜索结果 c = { 'query': request.GET['q'], 'resAmount': len(res), 'results': res, } else: return render_to_response('main.html') return render_to_response('result.html', c) # 展示搜索结果

    7.2 搜索迅速第一次搜索时,可能因为倒排索引index的取出时间较长而搜索缓慢,但一旦index取出,对于70000余条新闻的搜索将非常迅速,秒出结果。
    参考资料scrapy爬虫框架入门实例
    笔记:scrapy爬取的数据存入MySQL,MongoDB
    搜索那些事 - 用Golang写一个搜索引擎(0x00) —- 从零开始(分享自知乎网)
    Whoosh + jieba 中文检索
    利用whoosh对mongoDB的中文文档建立全文检索
    Django 创建第一个项目
    Django模板系统(非常详细)
    1 评论 0 下载 2019-05-05 23:07:44 下载需要10点积分
  • 基于JSP的MVC框架实现的图书推荐系统展示平台网站

    摘 要推荐系统是目前互联网中最常见的一种智能产品形式。由于网络中信息量的快速增长以及图书出版行业出版量的攀升,人们需要一种办法,来解决信息过载的问题。此外,用户访问网络是为了获取信息,但并不是所有的访问都有很强的目的性,所以对于这些没有明确的目的的访问,就需要智能系统把一些用户可能感兴趣的信息推送给用户。基于这些需求,图书网站的推荐功能就变得非常重要。
    本文首先对图书推荐系统的发展历史做了介绍,然后对开发图书推荐系统所需的项目管理工具(Maven、Git)、数据持久化工具(MyBatis,Spring MVC框架)和Bootstrap前端开发框架进行了简单分析,在此基础上,设计并开发了一套基于Web的图书推荐系统展示平台,主要工作可概括为四个方面。

    对图书推荐系统的结构进行了重新设计。主要是在Spring MVC框架的基础上,将系统分为了三层:Web层、服务与模块层、数据层,并对每层的结构与需要完成的功能做了定义。
    基于MySQL数据库管理系统,设计并建立了图书推荐系统所需的数据库,该数据库的数据共分为三个部分:原始数据、清洗后数据和用户数据。
    从便于操作和使用的角度出发,设计了图书推荐系统的页面,主要包括首页、搜索、展示、登录、注册等页面。
    对整个开发过程以及系统组成的三个主要类:控制器类、模块类与视图类进行了分析。

    经过后期的数据库优化与功能测试,系统与同类网站相比,性能良好。
    关键词:基于Web的图书推荐系统;展示平台;MVC框架;Web系统设计
    AbstractRecommender system is one of the most common intelligent productform in the internet recently. Since the growth of the information in thenetwork as well as the growth of the amount of books, people need to solve theproblem of information overload. Meanwhile, the users access to the network toobtain information, but not all have a strong purpose. So the system must pushsome information that user might be interested in to who accesses the websitewithout strong purpose. That is why it is important for website to providerecommendation information.
    First of all, we described the history of book recommender system.Then, made an introductory of the tool and frameworks used in development:Maven, the project management tool, Git, the version control system, MyBatis,the SQL Mapping Framework for Java, Spring MVC framework and Bootstrap, thefront-end framework. Finally, designed and developed a display platform ofweb-based book recommender system on that. The main work is as follows.

    Made redesign of the structureof the book recommendation system. Divided the system into three levels: theweb level, the service and model level and the data level based on the SpringMVC framework. Made the definition of the structure and functions to be done oneach layer.
    Designed and built the databaseof the book recommender system based on the MySQL database management system.Database is divided into three parts: Original data, washed data and user data.
    From the perspective of the easeof operation and use, designed the pages of the book recommender system. Pageshave been divided into index, search, display and login and register parts.
    Made analyses of the wholeprocess of development and the three main classes: controller, model and view.

    After database optimization and functional testing, system performsgood compared with similar sites.
    Key Words:Web-based BookRecommender System;Display Platform;MVC Framework;Web System Design
    引 言图书推荐功能在图书馆网站,图书销售网站,以及图书分享网站中都占有很重要的地位。它可以根据长尾理论挖掘图书数据,改善用户体验,增加用户的粘性,解决信息过载问题。
    本论文的目的就是要构建一个图书推荐系统的展示平台,将图书信息以及推荐内容,显示在页面之上。并且支持用户的注册登录,用来提供数据,使得推荐算法可以依照此数据来计算出用户喜好,进而向用户推送推荐信息。
    在推荐系统领域,最为成功的该属亚马逊网站,在亚马逊的收入中,有20%~30%的都来自于推荐系统。而在图书馆等非盈利性网站,图书推荐系统也对优化用户的浏览体验以及均衡每本书的借阅率,都有促进作用。
    系统后台是基于Java的Spring MVC框架与Tomcat服务器,前台基于浏览器、HTML与jQuery页面展示技术,数据库基于MySQL开源数据库。利用MVC框架,可以方便地构建出健壮、扩展性强的应用。MySQL数据库,作为最热门的开源数据库,提供了完整的关系数据库支持与成熟的数据存储解决方案。浏览器展示技术,使用户不需要在操作系统中安装独立的应用,并且使得系统的访问不局限于某个操作系统,适用面变得更广。系统提供推荐内容的展示,图书排行的展示,图书搜索,图书详细内容展示,用户登录注册等基本的图书推荐系统所具有的功能。界面使用Bootstrap框架,布局对用户更加友好。
    整个系统通过实现一个轻量的框架,来提供完整的图书推荐功能,后续的功能可以方便地在此基础上扩展。相对于其它的系统,有小巧、灵活的优点,并且本系统全部采用开源软件,因此几乎为零成本。在引用第三方库的过程中,不对其源码进行修改,减少耦合,使得之后第三方库的升级也不会对系统有大的影响。系统在一台机器上部署,并且在同一网段的另一台机器上访问测试后,性能表现良好。
    1 文献综述如今,推荐系统无处不在。在网上逛商城,购物,在音乐网站听歌,在社交网站发表自己的感受以及分享照片,网站服务提供商都会收集用户的访问记录以及用户的喜好,对用户的行为进行分析并且根据用户喜好以及用户群体统计信息,给用户提供相似物品的推荐以及广告推送,进而增加商家的销量,提高网站质量。
    一般认为,推荐系统这个研究领域源于协同过滤算法的提出。从它的诞生到现在20多年中,很多学者和公司对推荐系统的发展做出了重要的贡献。随着信息技术和互联网的发展,人们逐渐从信息匮乏的时代走入了信息过载的时代[1]。而图书出版物等作为一个传统的信息载体,在人类发展的过程中不断增多,一些大的互联网公司与网络图书销售商,比如谷歌、亚马逊等,也一直在为图书的数字化做着贡献。从2004年谷歌宣布他的图书搜索服务之后,到2012年,共有两千万本图书扫描、经由光学字符识别并存储于数字化数据库中作为搜索数据[2]。这些数据为图书推荐提供了丰富的基础。
    本系统采用BS结构,对数据库中的图书内容进行查询、处理,对查询结果进行展示,并且提供用户注册登录以及采集用户访问记录的功能。在服务器端采用Spring MVC框架与对象持久化技术对图书信息进行处理,在客户端使用浏览器技术对数据进行展示与交互,最终完成图书通过WEB平台展示、推荐与相关图书搜索的功能。
    1.1 课题背景1.1.1 图书推荐系统发展背景随着互联网的快速发展,网络中的图书信息量迅速增长,图书种类也日趋繁多,用户通过互联网要获得自己感兴趣的图书文章需要花费越来越多的时间。由此催生了图书推荐系统。图书推荐系统的基本作用是依据用户的访问记录,特定行为,分析用户的喜好,主动向用户推荐可能喜欢的图书与文献给用户,供用户参考[3]。推荐系统满足了用户个性化的需求,节省了用户搜寻信息的时间,获得和用户喜好相关的最热门最新的图书。在许多商务网站,社交网站中,都使用推荐系统来向用户推荐商品。
    在线售卖领域,亚马逊拥有最好的图书推荐系统。在过去的十多年里,亚马逊投入了大量的精力去建立一个包含大众推荐和个人记录的高效个人推荐系统,其最显著特点就是所有的推荐都建立在对顾客以往的浏览记录和购买记录之上[4]。
    亚马逊可以向用户精确的投放畅销书以及经典书推荐信息,每月有评有畅销书排行榜,通过简洁美观的介绍与醒目的导航,引导读者阅读与购买。另外,在畅销书的介绍中,还有本书在相关的分类栏目中的排名,并且有链接指向此分类的畅销排行榜,读者可以方便的查询同类书中最畅销的书籍。在书籍介绍底端还有购买过此书的人还购买了的书籍,购买的比例,以及同类书籍的推荐信息。在首页还有促销书的推荐,用于吸引没有明确目的,而想要以优惠的价格购书的消费者。在经典书方面,亚马逊推出年度畅销图书排行,年度编辑推荐100本畅销书等手段,依据惯性定律,进一步推动图书的销售。其中排序规则还根据用户的评价,人气、出版日期等,迎合不同人的喜好。
    1.1.2 主要技术发展背景Spring框架是一个开源的应用框架,基于Java平台的控制反转容器。第一个版本是Rod Johnson在他2002年十月出版的《ExpertOne-on-One J2EE Design and Development》书中发布的。第一次在Apache 2.0 license下发布是在2003年六月,在2004年三月,发布了第一个里程碑:1.0版本。在2006年,Spring框架1.2.6版本获得了Jolt productivity award和JAX Innovation Award。当前的版本3.2.2是在2013年三月发布的。
    Spring Framework的核心特性可以被用于任何的Java应用。尽管SpringFramework没有强加任何特殊的编程模块,它依旧在Java社区变得流行,并且有取代EnterpriseJavaBean模块的趋势。
    在2001年,Clinton Begin开始一个叫做iBATIS的项目,刚开始,开发的重点是一个加密的软件解决方案。iBATIS项目发布的第一个软件名字叫做Secrets,一个个人的数据加密和登录工具。Secrets完全的用Java实现,并且在开源协议下发布。
    2002年,Clinton开发了一个应用叫做JPetStore来展示Java可以比.NET更高效,JPetStore 1.0影响很大,并且其中用到的数据库层吸引了社区的注意。很快,iBATISDatabase Layer 1.0项目启动了,其中包括两个组件:iBATIS DAO和iBATIS SQL Maps。2004年,iBATIS 2.0发布,它是在保持原有特性上的全新设计。Clinton将iBATIS这个名字和源代码都捐献给了Apache SoftwareFundation,这个项目在ASF一直持续了六年。最终,iBATIS DAO被抛弃了,因为有更好的DAO框架的出现,比如Spring Framework。
    在2010年5月19日,iBATIS 3.0发布了,同时,开发团队决定将项目转移到Google Code。由于iBATIS这个名称已经捐赠给了ASF,所以项目改用了新名称MyBatis。
    jQuery是一个多浏览器的JavaScript库,目的是简化客户端的HTML脚本编程。John Resig在2006年一月发布,目前有一个Dave Methvin领导的开发小组进行开发。在一万个最热门的网站中,他被65%的网站使用。jQuery是目前最流行的JavaScript库。
    MySQL是世界最广泛使用的开源关系数据库管理系统。它作为一个系统服务,允许多用户访问多个数据库。
    MySQL开发项目将代码依照GNUGeneral Public License发布。MySQL被一家瑞典的公司MySQLAB拥有并且提供赞助,这家公司现在隶属于Oracle。
    1.2 开展研究的意义图书推荐系统web平台用于支持图书内容的获取和图书推荐的展示。如果没有此平台,那么图书推荐系统就无法收集用户行为,统计用户喜好,展示推荐结果以及实现推荐系统的原有意义[5]。任何一个推荐系统都需要网络或者客户端平台来展示[6]。而构建这样一个后台服务器与浏览器客户端共同协作展示的平台,对于图书推荐系统具有重要的意义。
    1.3 论文研究内容本课题意图开发一套轻量、扩展性强、功能完善,性能良好的图书推荐系统。系统的最终目标是实现对图书内容进行展示、查询、用户登录注册,还有推荐信息的展示功能。用户通过浏览器与后台系统的Java Servlet、数据库交互,完成展示、查询与用户管理的目的。
    研究的着重点在于通过现有流行的开源系统、框架,来搭建轻量级的目标Web系统,在实现过程中更注重于代码结构与开发方法,所以并不追求功能的繁杂冗余。系统中数据来源于豆瓣,数据的抓取不是本课题研究的内容。为了使数据适用于Web系统,重新构建了表,并对数据进行了二次清洗。由于是展示平台,并不涉及图书推荐算法的实现与搜索功能的完善,所以搜索结果由数据库查询获得。但是在开发过程中为图书推荐与社会化图书搜索预留了接口,可以方便的加入这些功能。
    1.4 论文的组织结构
    第一章,文献综述。先讲了课题的背景,从图书推荐历史和技术发展史两个方面介绍,之后介绍了开展研究的意义,最后明确了研究的工作重点。第二章,框架与工具介绍。对Maven、Git等项目管理工具,Spring MVC、MyBatis、Bootstrap、jQuery等开发框架进行了介绍。第三章,基于Web的图书推荐系统展示平台的设计。对此Web系统所用到的数据库结构、页面原型、模块组成、总体的功能进行了论述。第四章,基于Web的图书推荐系统展示平台的实现。介绍了对数据的二次清洗、数据库的创建、数据的导入、工程的搭建、模块的开发以及测试等。并介绍了测试过程中做的一些性能优化工作。最后,结论。对本系统的优缺点做了一个总结,展望了一下未来的发展方向。
    2 框架与工具介绍2.1 Maven介绍2.1.1 Maven概述Maven是一个主要用于Java项目的自动化构建工具。Maven与Apache Ant工具具有相似的目的,但是他们是基于不同的理念并且以不同的方式来工作。Ant还可以用来构建和管理C#,Ruby,Scala以及其他的语言开发的项目,但是Maven原生并不支持这些。Maven项目由Apache Software Fundation托管,之前是Jakarta Project项目的一个部分[7]。
    Maven使用XML文件来描述需要构建的软件项目、项目的依赖模块和组件、构建顺序、目录结构以及需要的插件。他具有预定义的目标来实现确切的任务,比如编译源码并打包。
    Maven动态地从一个或多个库中下载Java库和Maven插件,比如Maven 2 Central Repository,并且将下载的内容保存到本地的缓存中。这个本地的下载缓存可以被本地项目更新,公共的库也可以被更新。
    Maven使用基于插件的体系来构建,他允许通过标准的输入控制任何的应用。理论上说,这将允许任何人为任何语言来在这个平台上编写插件。实际上,支持和使用除Java外其它语言的插件数量已经微乎其微。目前,只有支持.NET框架以及一个C/C++的原生插件还在被维护。
    2.1.2 Maven概念项目对象模型(POM):一个项目对象模型提供一个项目的所有配置属性。一般配置包括项目名称,owner和它的依赖。也可以通过插件,配置构建过程的各个阶段。比如说,用户可以配置编译插件,让它使用Java 1.5来编译,或者指定在一些单元测试失败以后,依旧打包工程。大的项目应该分成几个模块或者子项目,每个模块拥有自己的POM。用户可以编写一个根POM,通过这个根POM来使用一条命令来编译所有的模块。POM也可以从其它POM文件继承配置信息。所有的POM文件默认继承自Super POM。Super POM提供默认的配置,比如默认源代码目录、默认插件,等等。
    插件:大部分Maven的功能是通过插件来实现的。插件提供一组目标,并且可以通过以下的语法来执行:
    mvn [plugin-name]:[goal-name]
    比如说,一个Java项目可以使用compiler-plugin的complile-goal来编译:
    mvn compiler:compileMaven插件提供构建、测试、源码控制管理、运行web服务、生成Eclipse项目文件等等功能。插件由pom.xml文件中的<plugins>标签区域引入并且配置。
    然而,如果构建、测试、打包一个软件项目需要手动运行下面每条goal,那么,它将会变得非常笨重:
    mvn compiler:compilemvn surefire:testmvn jar:jarMaven的生命周期概念处理这类问题。
    插件是扩展Maven的主要方式。可以通过继承org.apache.maven.plugin.AbstractMojo类来开发Maven插件。
    构建生命周期:构建生命周期是一个用来给出为了达到goal所执行语句顺序的列表。Maven的一个标准生命周期叫做“默认生命周期”,它包括以下语句:

    process-resourcescompileprocess-test-resourcestest-compiletestpackageinstalldeploy
    插件提供的goal可以与不同的生命周期阶段相关联。比如说,默认情况下,“compiler:compile”的goal与编译阶段有关,而goal“surefire:test”与测试阶段有关。考虑下面的命令:
    mvn test
    当以上的命令被执行,Maven运行所有的在test语句之前的goal,直到test语句。在这种情况下,Maven运行“resources:resources”goal,然后是“compiler:compile”,等等,直到最终运行“surefire:test”goal。
    Maven也有标准用来清理项目和生成项目站点的语句。如果清理是默认生命周期的一部分,那么项目将在每次构建的时候被清理,这显然不是想要的。所以,清理有它自己的生命周期。
    标准的生命周期允许新用户能够通过一个简单的语句准确的构建、测试和安装每个Maven项目:
    mvn install依赖:Maven的依赖处理机制围绕一个坐标系统识别单个软件库或者模块。比如说,一个项目需要Hibernate库,仅仅需要在POM文件中声明Hibernate项目,Maven将自动下载依赖和Hibernate自身的依赖,并且把它们存储在本地的仓库中。Maven 2 CentralRepository是默认的用来搜索的库,但是也可以在POM文件中自定义仓库。
    还有一些其他的搜索引擎,比如说Maven Central,可以被用来去不同的开源库和框架中寻找模块。
    在同一个机器上开发的项目之间可以通过本地仓库来互相依赖对方。本地仓库是一个简单的目录结构,充当下载的依赖包的缓存与本地构建的项目的集中存储的地方。Maven命令mvn install构建一个项目,并且把它的二进制文件放到本地仓库中。然后其它的项目可以通过在POM文件中添加项目来引用这个工程。
    2.2 Git介绍2.2.1 Git概述Git是一个分布式的版本控制系统和源代码管理系统。它最初是Linus Torvalds为Linux内核开发而设计开发的,从那以后,Git就被许多其它的项目用来管理代码[8]。每个Git工作目录都是一个完整的仓库,保存着完整的历史和全部的版本跟踪能力,不需要依赖于网络连接或者一个中央服务器。Git是基于GNU GeneralPublic License version 2的开源软件。
    Git设计灵感来自于BitKeeper和Monotone。Git最初被设计成一个底层的版本控制系统引擎,在它上方其他人可以编写前端,比如说Cogito和StGIT。然而,核心的Git项目最终变成一个可以直接使用的完整的版本控制系统。由于受BitKeeper的严重影响,Torvalds故意地试着避免传统的方法,最终实现了一个独一无二的设计。
    2.2.2 Git特性Git的设计来源于Torvalds在开发Linux过程中积累的管理大的分布式项目的经验和对文件系统性能的知识,以及在短期内构建一个可以工作的系统的需求。这些影响导致了以下实现方案:
    1.对非线性开发的强大支持
    Git支持快速的分支和合并操作,并且包含专门的工具用来可视化和导航一个非线性的开发历史。Git的一个核心设想是:由于项目被分给好多个人来完成,修改会更多的被合并,而不是被写入。在Git中,分支是非常轻量的:一个分支仅仅是一次提交的关联,通过其父提交历史,整个分支结构就可以创建出来。
    2.分布式开发
    就像Darcs、BitKeeper、Mercurial、SVK、Bazaar和Monotone,Git给每个开发者一份整个开发历史的本地副本,并且修改记录会从一个这样的本地仓库复制给另一个。这些修改作为附加的开发分支导入进来,并且可以合并到本地的开发分支中。
    3.兼容已存在的系统和协议
    仓库可以通过HTTP、FTP、rsync或者通过建立在纯socket、ssh、或HTTP上的Git协议来推送。Git还有一个CVS服务器模拟,用来让使用CVS客户端和IDE插件的用户来使用Git仓库。Subversion和SVK仓库可以直接使用git-svn。
    4.高效处理大型项目
    Torvalds描述Git处理速度非常快、可扩展,并且Mozilla对其做的测试显示,它比一些版本控制系统快一个数量级,从本地存储的仓库获取比从远程服务器快一百倍。Git甚至在项目历史变得很大的时候速度依旧不会减慢。
    5.历史记录加密认证
    Git历史记录以这样一种方式存储:某次提交的id号取决于之前的完整的开发历史。一旦被发布了,就不可能再去修改旧的版本而不产生记录。这种结构就像一个hash树,但是在每个节点和叶子上,都有附加的数据。
    6.基于工具的设计
    Git是C语言程序,它有一些shell脚本来对其进行封装。尽管大部分的脚本为了提升速度和可移植性,已经用C语言重写过,但是依旧有一些并且很容易的就可以将组件和Git连接起来。
    7.可控的合并机制
    作为工具设计的一部分,Git具有对不能完成的合并有良好的定义模块,并且它还具有多种算法来完成合并。不能自动合并的部分它会最终提示用户,并且由用户来手动编辑。
    8.垃圾回收机制
    放弃等操作会在数据库中留下无用的对象。这是基本上是逐渐增长的历史记录的一个小碎片。Git将会在足够多的松散对象积累够之后,自动的进行垃圾回收。垃圾回收也可以使用git gc –prune命令来调用。
    9.定期对象包装
    Git将每个新创建的对象作为一个独立的文件来保存,尽管每个都会压缩,但是这依旧会占用大量的空间并且降低效率。这个问题是用一种叫做packfile的单一文件存储大量的对象在一个包中来解决的。每个packfile创建一个对应的索引文件,用来表示packfile中的每个对象的偏移地址。新创建的对象依旧独立存储,定期的打包,以保持空间利用率。打包仓库的过程会非常消耗计算机资源。相对于允许对象松散的存在于仓库中,git允许在空闲时间花费较大的开销来将他们打包。Git会定期的自动重新打包对象,不过,也可以使用git gc命令来手动打包。为了保证文件的完整性,每个packfile和它的索引内部都有SHA-1校验码,并且packfile的文件名包含一个SHA-1校验码。输入git fsck命令即可验证完整性。
    2.3 MVC模式与SpringFramework框架2.3.1 MVC模式MVC模式是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
    MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观[9]。软件系统通过对自身基本部分分离的同时也赋予了各个基本部分应有的功能。组件合作关系如图2.1所示。

    模型(Model):“数据模型”用于封装与应用程序的业务逻辑和数据处理相关的方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖于“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中的数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解数据模型上发生的变化。
    视图(View):视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。
    控制器(Controller):控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并做出响应。“事件”包括用户的行为和数据模型上的改变。
    2.3.2 Spring MVC框架Spring Framework提供它自己的MVC web应用程序框架,这并不是开发之初计划的。由于当时流行的Jakarta Struts web框架的设计很糟糕,并且其他框架也有许多不足之处,Spring开发者决定去编写他们自己的web框架。最重要的一点,他们觉得在表现与请求处理层之间没有完整的分离,并且请求处理层和模块层也没有完全分离。
    就像Struts,Spring MVC也是一个基于请求的框架。每个接口的目的是让Spring MVC用户能够清晰、容易的实现MVC框架的应用。所有的接口都是与Servlet API紧耦合的[10]。这个对Servlet API的紧耦合被某些开发者看做是Spring的失败,它不能提供一个高层次的对基于web的应用的抽象层。然而,这样耦合确保了Servlet API能够给开发者提供一个高度抽象的框架来使得开发变得容易[11]。
    Spring MVC框架围绕一个核心servlet来给控制器分发请求并且提供一些其它的功能来方便web应用的开发,Spring的DispatcherServlet就是用来干这些的。它将Spring IoC容器完全集成在一起,这样你就可以使用所有其它的Spring特性。
    Spring Web MVC DispatcherServlet的请求处理工作流如图2.2所示。DispatcherServlet是一种“Front Controller”设计模式的表现(这种设计模式在许多其它的web框架中也很常见)。

    DispatcherServlet是一个真实存在的Servlet(它继承自HttpServlet基类),并且在web应用的web.xml文件中声明。那些你想要DispatcherServlet处理的请求必须在同一个web.xml文件中使用URL映射来映射到这个Servlet。这是标准的J2EE servlet配置。图2.3是对DispatcherServlet的声明和映射。

    在上面的配置示例中,所有的以.form结尾的请求都会被”example” DispatcherServlet来处理。这仅仅是配置Spring Web MVC的第一步。
    在Web MVC框架中,每个DispatcherServlet都有自己的WebApplicationContext,这个WebApplicationContext继承了根WebApplicationContext定义的所有的beans。图2.4为Spring Web MVC中的上下文层次关系。

    框架将会在初始化DispatcherServlet的时候,在你web应用的WEB-INF目录中寻找一个名字叫[servlet-name]-servlet.xml的文件,然后创建在那个文件里定义的beans。
    WebApplicationContext是一个对单纯的ApplicationContext的扩展,对web应用增加了一些额外的特性。它区别于普通的ApplicationContext的地方是,它可以解析主题,并且它知道自己与哪个servlet相关联。
    Spring DispatcherServlet有一些特定的beans来实现处理请求和获取正确的视图返回给用户。这些beans被包括在Spring框架中并且能在WebApplicationContext中配置,就像其它的beans一样的配置方式。
    一些比较重要的接口定义以及他们的功能列举如下:

    HandlerMapping:选择对象来处理来自内部或者外部的请求。HandlerAdapter:对请求进行处理。Controller:介于Model和View之间来管理请求和返回合适的响应。他就像一个门,来对传入的请求进行处理。它从Model获取数据,传递给View并将View展现出来。View:用于向客户端返回数据。一些请求可能会直接请求到视图,而不经过模块部分,其它的请求三者都要经过。ViewResolver:根据逻辑名称为视图选择一个View。LocaleResolver:获取并且保存用户的位置信息。MultipartResolver:提供对文件上传的请求的封装。
    以上的每个接口对整个框架都有重要的作用。这些接口提供的抽象层用处非常大,所有继承自这些接口的类都按照同样的特性建立在Servlet API之上。开发者可以自由的去编写他们的实现类。Spring MVC使用Java的java.util.Map接口作为数据Model,数据Model与View共同生成最终的返回页面[12]。
    2.4 MyBatis介绍MyBatis是一个在Java和.NET平台的持久层框架,它将SQL声明与存储过程使用XML描述[13]。MyBatis是一个自由软件,基于Apache License 2.0发布,它的原名为iBATIS[14]。
    MyBatis允许你可以使用所有的数据库功能,比如存储过程、视图、任何复杂的查询,以及数据库厂商所专有的功能。它经常被用来处理遗留数据库、规范化的数据库或者是需要完全的控制SQL执行的时候。
    它相对于JDBC简化了编码,SQL语句仅仅需要一行代码便可以执行。这样便节约了时间,避免了一些常见的失误,比如忘记关闭数据库连接、编写了一个错误的数据映射、超过了结果集的数量限制或者是查询结果不仅仅是一条。
    MyBatis提供了一种映射引擎,将SQL结果映射到对象树中。SQL语句可以通过使用内置的有XML类似语法的语言来动态的建立,或者通过使用Velocity集成插件来使用Apache Velocity建立。MyBatis集成在Spring Framework和Google Guice中,这个特性可以允许自由的构建商业应用并且不需要调用任何的MyBatis接口。
    MyBatis支持声明式的数据缓存。MyBatis集成了:OSCache,EHcache,Hazelcast和Memcached,并且支持集成自定义的缓存工具。
    MyBatis提供一套自动生成代码的工具:MyBatis Generator。MyBatis Generator将会检查一个数据库表(或者许多表),然后生成MyBatis项目用来支持增删改查操作。
    2.5 Bootstrap介绍2.5.1 Bootstrap概述Bootstrap是一个用来创建网站和web应用的工具集。它包含许多基于HTML和CSS的设计模板:排版、表单、按钮、图表、导航、其他的界面组件以及可选的JavaScript扩展。它是GitHub上最流行的项目,NASA和MSNBC网站都在使用此框架。
    Bootstrap有相对不完整的对HTML 5和CSS 3的支持,但是它兼容所有的主流浏览器。从2.0版本开始,它开始支持响应式设计。这意味着网站页面的视图设计根据设备的特点来动态的调整。
    Bootstrap是Twitter发布在GitHub上的开源软件。开发者可以参与项目并且对平台贡献自己的力量。
    2.5.2 结构和功能Bootstrap是模块化的,包含一系列的LESS样式,用来实现工具的不同部件。一个叫做bootstrap.less的样式表包含了组件的样式。开发者可以选择自己需要的组件来创建自己的bootstrap.less文件。使用LESS样式表语言允许用户使用变量、函数、运算符、嵌套选择器,以及所谓的mixins。
    自从2.0版本开始,在Bootstrap网站上添加了自定义的配置选项。开发者可以在一个表单上选择想要的组件和调整参数,然后生成配置好的预编译CSS样式表。
    1.栅格系统和响应式设计
    Bootstrap默认支持940像素宽度的栅格布局。另外,开发者可以使用一个可变宽度的布局。工具集中有四个参数来使用不同的分辨率和设备类型:手机、竖屏、横屏格式、平板电脑、有低分辨率和高分辨率的电脑。页面会自动根据这些分辨率来调整列的宽度。
    2.CSS样式表
    Bootstrap提供一系列的样式表来为主要的HTML组件提供基本的样式定义。这样可以对不同的浏览器和不同宽度的设备提供一套统一的文字格式、表格、表单项目布局。
    3.可重用的组件
    除了常用的HTML元素,Bootstrap包含一些其它的样式元素:带有高级特性的按钮(比如按钮组、带有下拉选择的按钮、导航列表、横向、纵向的标签、面包屑导航、分页等等)、标签、高级的排版功能、缩略图、带格式的警告信息以及进度条。
    4.JavaScript插件
    JavaScript组件基于jQuery JavaScript库。它提供附加的用户界面元素,比如对话框、工具提示以及轮播。他们也扩展了一些已经存在的页面元素,包括:一个输入框自动完成的功能。
    2.6 jQuery介绍jQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作。目前是由 Dave Methvin 领导的开发团队进行开发。全球前10000个访问最高的网站中,有59%使用了jQuery,是目前最受欢迎的JavaScript库[15]。
    jQuery 是开源软件,使用MIT许可证授权。jQuery的语法设计使得许多操作变得容易,如操作文档对象、选择DOM元素、创建动画效果、处理事件、以及开发Ajax程序。jQuery 也提供了给开发人员在其上创建插件的能力。这使开发人员可以对底层交互与动画、高级效果和高级主题化的组件进行抽象化。模块化的方式使 jQuery 函数库能够创建功能强大的动态网页以及网络应用程序[16]。
    jQuery有下列特色:

    跨浏览器的DOM元素选择DOM巡访与更改:支持CSS 1-3事件(Events)CSS操纵特效和动画(移动显示位置、淡入、淡出)Ajax延伸性(Extensibility)工具:例如浏览器版本(已取消自带,改由jQuery Migrate plugin外挂提供)和each函数。JavaScript插件轻量级
    jQuery 1.8.0版时(自带Sizzle.js):



    文件
    行数(行)
    大小(KB)




    jquery-1.8.0.min.js
    2
    91


    jquery-1.8.0.js
    9228
    254




    DHTML DOM选择器与链式语法
    经由jQuery的DHTML DOM选择器,可以更容易的操作在复杂的树状HTML中的任何DHTML DOM对象,并可用链式语法对同一对象的不同属性进行操作。
    例如:
    $("p.surprise").addClass("ohmy").show("slow");
    相当于:查找HTML的<p>标签,且其class为”surprise”的DHTML DOM对象,将其Class属性多加上一个”ohmy”(通常是配CSS的定义做显示时的配色修改),打开显示。


    CSS 1-3选择器:支持CSS选择器选定DOM对象。跨浏览器:跨浏览器的AJAX解决方式,支持InternetExplorer 6.0+、Opera 9.0+、Firefox 2+、Safari 2.0+、Google Chrome 1.0+简单:较其它JavaScript库更易于入门。
    2.7 小结本章简要介绍了开发过程中用到的几个比较重要的工具与框架。在项目创建和最后的部署过程中,Maven工具为项目的依赖的解决和编译打包提供了很好的解决方案。而在项目开发过程中,Git工具为代码管理、版本控制以及进度统计,都提供了很大的帮助[17]。
    本章还介绍了四种框架:Spring MVC、MyBatis、Bootstrap和jQuery。前两者是后台框架,提供了一系列的类与接口,用于实现系统功能、简化与美化代码结构设计,并提供了一些工具来方便开发者实现相应的功能[18]。后两者为前台框架,简化了前台的开发过程,提供封装好的方法来让前台交互更加方便,界面更加友好。这四种框架为开发的核心框架,它们极大的提高了生产率,并且使最终的产品不仅内部结构,而且外部表现都健壮、美观。
    3 基于Web的图书推荐系统展示平台设计3.1 系统总体设计3.1.1 总体功能描述本课题是要开发一套轻量级、功能完善的基于Web的图书推荐系统展示平台。利用此平台,对图书信息进行展示与推荐,对用户提供注册与登录功能。由于原始数据为从豆瓣依照网站网页结构抓取得来,并不适用于系统直接读取,于是需要将原始数据表格进行重新设计,遍历分离所需数据存入新设计的表中,使其可以更便捷的查询与处理。开发过程需要考虑Spring MVC框架,将功能按照模块、视图、控制器三部分分离,模块与视图适度的模块化使其可以较好的重用。beans使用注解来注入,这样可以提高小的个人项目的开发效率。在开发开始,配置Maven来解决需要的依赖包,创建Git仓库,来控制版本。
    3.1.2 系统模块组成首先将系统在Spring MVC的基础上分为了三层,分别为:Web层,服务及模块层,数据层,而Web层中,分为Controller与View模块,View为Controller服务,按照预定义的格式来展示Controller的数据。Controller将数据访问与一些公共的逻辑算法交给Model来处理,Model将处理结果交还给Controller。而Model类就像前面Controller给他的任务,负责与界面无关的逻辑计算与数据库的访问、以及其它格式数据的获取。结构如图3.1所示。

    Web层负责处理用户的请求,其中Controller会接收DispatcherServlet分发过来的请求,Controller调用服务与模块层中的模块,进过逻辑计算,生成最终的数据,将数据通过键值对的方式,将视图通过字符串方式传递给DispatcherServlet,DispatcherServlet再读取对应的View,使用View作为模板,生成最终的页面,返回给用户。
    服务与模块层负责逻辑计算与数据获取。其中MyBatis Mapping模块为通过MyBatis Generator自动生成的DAO类,以及自定义的DAO类,用于连接MySQL数据库并且执行增删改查操作。而逻辑计算与数据获取模块包含了公共方法类,某些特殊的算法计算,以及对配置文件的查询取值。
    最底下的数据层,包括数据库系统与文件系统,是用来存储数据与配置的层。其中数据库采用MySQL数据库,配置文件使用Java自带的.properties文件。
    三层之间是互相独立的,只有最近的两层之间可以访问:服务与模块层只可以访问数据层,而Web层只可以调用服务与模块层。其中,服务与模块层中的逻辑计算与数据获取模块,每个模块之间是相互独立的,模块与模块之间不可以互相访问,这样用来降低耦合性,每个模块完成一个完整的任务。由于Web请求的模式决定Web应用只能是被动接收请求,并且Web应用没有涉及费时的网络获取,在代码中没有回调函数,所以层与层之间的调用为单向的,即模块层只可调用数据层,让数据层来执行操作,然后返回数据给模块,Web层调用模块层,将一些逻辑计算与数据获取的过程交给模块来完成,结果返回给Web层,而不可能模块层主动的调用Web层,来对其中的值进行更改,而后返回给用户一个新的页面。在Web层中,View模块只负责对数据进行格式化,生成最终用户页面,因此,它只接收Controller模块的值,而与程序的其它层次模块之间不可以通信。这样,在编写Controller模块时,并不需要了解数据库的组织结构以及配置文件的具体文件名等,只需要知道调用哪个模块,将需要的参数传入模块,模块返回的值就是所需要的数据。而在编写View模块时,也不需要了解其它各个层次都有什么作用,只需要分析页面哪个部分的数据是动态获取的,然后将此部分数据安排给Controller,让Controller传过来就可以了,这样将不同模块之间的耦合性降到了最低。而Controller就像一个乐队的指挥,按照需求调用各个模块,让系统的各个部分井然有序的工作。
    3.2 模块详细设计3.2.1 数据库设计1.原始数据库
    原始数据库存储从豆瓣抓取下来的数据,分为三张表:book_author_info,book_online_info,book_publishing_info。
    book_author_info表存储作者信息,分为图书编号、作者姓名、作者简介与介绍四列。作者简介内容包括作者的生平以及与此书和作者都有关的一些事件介绍,介绍列与前者相同。作者姓名列存储了各个作者加国籍的信息,需要进行清洗。
    book_online_info表存储图书的一些社会化信息,分为图书编号、标签、访问次数、5星评价数量、4星评价数量、3星评价数量、2星评价数量、1星评价数量、想读用户数量、在读用户数量、已读用户数量、还想阅读的书 这十二列。其中标签列将所有的标签,带上打标签的次数都放到了同一个字符串中,需要对其清洗。
    book_publishing_info表存储了图书的出版信息,分为图书编号、ISBN号、书名、作者姓名、图书描述、图书目录、包装类型、定价、总页数、出版社名称、出版时间以及图书封面缩略图名称这十二列。作者姓名与book_author_info表的作者姓名列重复,而定价、总页数等数据使用varchar来存储,出版社也没有构建序号,不便于检索,所以这些内容都需要清洗整理。
    2.清洗后数据库
    清洗后的数据库是可以直接拿来网站使用的,从原始数据库中数据清洗整合出来的数据,分为九张表:book_info,tag_info,book_tag_relation,author_info,book_author_relation,nationality_info,publisher_info,binding_type,book_relation,内容如表3.1-3.9所示。
    book_info表内容



    表名称
    书籍详细信息表




    列名称
    图书编号、ISBN号、书名、书籍描述、书籍目录、包装类型序号、定价、页数、出版社序号、出版时间、封面图片名称、评论数量、5星评价数量、4星评价数量、3星评价数量、2星评价数量、1星评价数量、想读人数、正在读人数、已读人数


    描述
    其中书名数据类型由原来的text转换为varchar,便于构建索引,提高查询速度。将原先耦合在一起的包装、出版社数据独立出来,只在表中引入其序号,便于按不同类型来查询。将定价和页数的数据类型由varchar改为int,方便程序读取,提高查询速度。定价数据类型并没有采用double,因为它是固定的两位小数,精确到分即可,并没有必要采用比较大的double类型。



    tag_info表内容



    表名称
    标签内容表




    列名称
    标签序号、标签名称、标签数量以及标签等级


    描述
    标签序号为自动生成的这个标签唯一的序号,用来识别标签。标签名称是清洗出的单个的标签,使用varchar存储,便于生成索引,提高搜索速度,标签数量为在所有图书的标签中,标签出现的次数。



    book_tag_relation表内容



    表名称
    图书与标签关系表




    列名称
    图书编号、标签序号以及使用次数


    描述
    图书编号为book_info表中的主键,标签序号为tag_info表中的主键,使用次数为给这本书打这个标签的用户的数量。



    author_info表内容



    表名称
    作者信息表




    列名称
    作者编号、作者姓名、作者简介内容、作者的国籍编号


    描述
    作者编号为自动生成,是表中的主键,作者姓名是将原始数据中的作者姓名清洗出单个的作者后,放入表中的。改用varchar存储,便于生成索引。国籍编号为nationality_info的主键。



    book_author_relation表内容



    表名称
    书籍与作者关联表




    列名称
    图书编号、作者编号


    描述
    图书编号对应book_info表主键,作者编号对应author_info表主键。



    nationality_info表内容



    表名称
    国籍信息表




    列名称
    国籍编号、国籍名称


    描述
    国籍编号为自动生成的主键,国籍名称为从作者信息中解析出来的作者的国籍。



    publisher_info表内容



    表名称
    出版社信息表




    列名称
    出版社的序号、出版社名称


    描述
    出版社序号为自动生成的主键,出版社名称为从原始数据中清洗出来,转换为varchar格式的数据,方便生成索引以提高查询速度。



    binding_type表内容



    表名称
    包装类型信息表




    列名称
    包装类型序号、包装类型名称


    描述
    包装类型序号为自动生成的主键,而包装类型名称为从原始数据中清洗出来,转换为varchar类型的数据。



    book_relation表内容



    表名称
    相关借阅信息表




    列名称
    书籍编号、相关借阅书籍编号、相关借阅书籍名称


    描述
    书籍编号与相关书籍借阅编号都来自于book_info的主键。而相关借阅书籍名称为书籍的字符串名称,因为有部分相关借阅书籍可能不在数据库中,所以有必要将其字符串名称存于表中,可以拿去搜索或者进行其他一些操作。



    3.用户数据
    用户数据是用户的登陆注册以及访问记录的表。其中的数据为Web应用自己生成,而不是预先装入系统之中的,分为:user_info,user_visit_history,user_search_history,内容如表3.10-3.12所示。
    user_info表内容



    表名称
    用户信息表




    列名称
    用户编号、用户名、密码、用户邮箱、用户状态、用户口令


    描述
    其中用户编号为自动生成的主键,用户名为用户注册时所起的名称,与密码一起用于登录。密码使用SHA算法加密,用户邮箱为注册时填写,用于激活账户与找回密码之用。用户状态分三种:0:已注册,未激活,1:注册并激活,2:密码已丢失,需要重新找回。用户口令取自第一次登录的session id,用于保持用户持久登录状态。



    user_visit_history表内容



    表名称
    用户访问记录表




    列名称
    用户编号、用户访问图书编号、访问时间、访问来源、访问来源图书编号


    描述
    用户编号对应user_info表中的主键,用户访问图书编号为用户打开的图书介绍页面中图书的编号,访问时间为打开图书介绍页面的时间,访问来源分三类:0:首页,1:搜索结果,2:其它图书推荐,其中访问来源为2的,需要填写访问来源图书编号。



    user_search_history表内容



    表名称
    用户搜索记录表




    列名称
    用户编号、用户搜索关键词、搜索时间


    描述
    用户编号对应user_info表中的主键,搜索关键词为用户在搜索框中输入的关键词,搜索时间为发生搜索事件的时间。



    3.2.2 页面原型设计使用快速原型工具Axure RP Pro,根据功能设计了需要实现的页面的原型:首页、搜索结果页、图书展示页、注册页面、登录页面。生成的首页原型效果如图3.2所示。

    首页顶部包含一个logo,链接到本页;搜索框,提供对图书的搜索入口。以及登陆和注册链接,用于用户的注册与登录管理。正文部分分为四个大模块,名称分别为:相关图书推荐、分类热门图书、图书分类以及图书排行。图书推荐模块列出单本书的缩略图与简要介绍,而分类热门模块列出了几个大的图书分类,以及几本此分类下的比较热门的图书。图书分类模块列出了所有的图书分类,用户可以直接点入查看此分类下的所有图书。图书排行列出前九本最热门的图书。页脚部分注明页面版权信息,以及创建年份。
    搜索页面页眉页脚与首页相同,正文部分为一个搜索结果列表,显示搜索结果中的15条记录,每条记录显示图书缩略图、书名、作者、出版社、出版日期、价格以及评分。正文底部是分页,列出了结果的页数,可通过点击来查看后面的搜索结果。右侧列出了热门图书列表,用于向用户推荐。
    图书展示页面页眉页脚与首页也相同,正文部分分四大块,第一块为图书基本信息,包括标题、缩略图以及一些图书在版编目信息:作者、出版社、出版时间、页数、定价、装帧、ISBN号。同时还显示评分以及各个星评分数量。第二块为内容简介,是对书内容的简要介绍以及图书目录。第三块为作者简介,是对图书作者以及译者的简要介绍。第四块为相关推荐,展示阅读此书的人还阅读了的书籍。由于原始数据并不包含用户评论,因此用户评论的内容并没有加入展示。
    注册页面和登录页面较为简单,用户填写用户名、邮箱、密码、确认密码,之后点击注册即可。登录时,用户输入用户名、密码,然后登录系统,会跳转到首页,首页右侧顶端登录注册不再显示,改为用户名与退出。
    3.3 小结本章介绍了本课题所研究的基于Web的图书推荐系统展示平台的系统总体设计与详细设计。总体设计主要讲述了系统设计的层次结构,并且规定了系统各层各模块之间的组织结构与通信规则。详细设计部分对数据库进行了设计,列出了各个表的结构与描述。并且使用页面原型工具构建了简单的页面,来作为之后页面开发与功能模块划分的依据。总体合计与详细设计在系统开发之前,对之后系统的结构与功能都起到非常重要的影响,结构的好坏直接影响到系统的性能。此章是下一步实现系统的必要步骤和重要依据。
    4 基于Web的图书推荐系统展示平台实现4.1 环境的搭建4.1.1 数据库的建立与数据的导入PowerDesigner创建一个物理数据模型,配置好数据库类型,添加表结构,将在详细设计中所设计的数据库信息与列信息、自增列属性输入到表结构中,生成如图4.1所示的物理结构设计图。

    使用其自动生成工具,生成用于创建数据库的SQL脚本。之后,使用MySQL工具导入到数据库中。同时,将原始数据也使用MySQL工具导入到数据库中。
    4.1.2 工程建立使用Eclipse创建一个Spring MVC项目,系统会自动生成一套目录结构,如图4.2所示。


    src/main/java目录用来存放项目的主体部分的源代码,所有的Controller模块、Model模块,以及DAO的Java类,都放在这里,在发布的时候,这里的源码会在编译成class文件后,放入WEB-INF目录下的classes目录。src/main/resources目录用来存放项目的配置文件以及MyBatis的Mapping文件。在部署过程中,也会被放入WEB-INF目录下的classes目录中。src/test/java目录用来存放项目的测试类,src/test/resource目录用来存放项目的测试配置文件,这些都会在部署时,放入WEB-INF目录下的test-classes目录中。JRE System Library包含系统中安装的JRE的库,在项目创建时,可以选择版本。Maven Dependencies包含了在Maven的POM配置文件中所配置的依赖包,这些包在工程创建时,由Maven从Maven仓库中下载到本地缓存,并且链接到工程中。src目录分main和test,而main/webapp目录下有resources与WEB-INF目录,其中resources目录是在servlet-context.xml中配置的,用于存放页面中的资源的目录,分为css、img、js三个目录,WEB-INF目录分为classes、spring与views目录以及web.xml文件,web.xml文件为Java Servlet的标准配置文件,Spring就在这里配置进去。classes为应用发布时,.class文件的目录,spring目录为spring配置文件存放的目录,用于修改配置,添加beans用于注入等。views目录为视图模块存放的地方,使用jsp作为视图文件。target目录为自动编译的目录,目录中有所有类、测试类的编译结果.class文件,以及Maven的配置文件pom.xml。pom.xml文件为Maven的配置文件,它包含了项目的基本配置、依赖包以及插件配置。项目创建时,默认只有Spring MVC的基本配置。
    4.1.3 版本控制为了开发的方便,防止不必要的损失以及对进度的掌控,项目一开始便进行了版本控制,在GitHub网站创建了一个私有仓库,项目的根目录下初始化了Git本地仓库,配置好全局变量:用户名、邮箱以及SSH key,项目目录下加入远程的GitHub仓库,之后便可以添加文件、提交更改并且推送到远程服务器上。
    修改提交的节点选择在每次一个功能完成之后或者是对之前的文件需要进行比较大的修改之前。功能完成之后提交,可以确保自己能够定期的跟踪到完整的可运行的项目,不至于两次提交之间项目变化过大,如果想要修改,那就不容易找到一个合适的检出时间点。进行比较大的修改之前提交,虽然可能一个功能并没有完成,但是修改过程中可能要参考到之前的部分功能,所以仍有必要将其保存提交。在修改完之后,最终确定了用新的方案,再次提交。
    4.1.4 MyBatis配置MyBatis官方提供了一个自动生成代码的工具:MyBatis Generator(MBG)。它会检测数据库的所有表,并且生成可以用来访问数据库表的代码。这样可以减轻最初访问数据库所需编写代码的工作量。MBG提供了所有常用的数据库操作:增删改查。对于单表的操作,只需要使用这一套生成的类即可,生成结果如图4.3所示。

    在生成的文件中,dao为mapper接口,存放TableNameMapper.java文件,用来在配置中注入或者使用SqlSession来获取实例,对数据库表执行增删改查操作。model为表结构的类TableName.java和查询条件构造类TableNameExample.java,TableName.java用于存储对应表的响应条目值,用来实现update和insert操作,以及查询出结果的存储。TableNameExample.java用来构造where语句,用于执行select操作。在数据库中有多于两个列的类型为TEXT或者BLOB,那么除了生成TableName.java,还会生成一种TableNameWithBLOBs.java的文件,其中TableName.java负责存储一般的数据类型,TableNameWithBLOBs.java文件负责存储TableName.java中所有数据之外,还包括了TEXT和BLOB类型的数据。mapper目录存储xml配置文件,用于支持在TableNameMapper.java文件中定义的操作。
    将代码和配置文件加入到工程中之后,会出现编译错误,显示一些引用的类不存在于工程中。查找原因,发现是因为项目中没有加入数据库与MyBatis的依赖,修改pom.xml配置文件,加入spring-jdbc、mybatis、mybatis-spring与mysql-connector-java依赖配置。
    在src/main/resources加入mybatis-config.xml,用来为MyBatis提供连接数据库的配置与Mapper类集合的配置。创建Mysql.properties文件,将配置写入文件中以便复用。
    4.2 数据的清洗由于原始数据并不能直接拿来使用,因此需要按照之前设计的数据库,将三个表中的原始数据清洗后,存入新设计的表中,程序流程如图4.5所示。
    程序会先定义起始和终止图书编号,之后,从第一个图书编号开始,通过主键,查询到图书的数据,将需要的值取出,比如作者信息。作者信息包括了作者国籍、作者姓名以及其它作者姓名,格式如图4.4所示。

    开始打算通过一个完整的正则表达式来对作者信息进行解析,但是由于Java的正则表达式并不能够分辨出中文标点与中文文字,因此,先对字符串做初步的清理:将“编著”、“译者”、“主编”替换为英文斜杠“/”来区分不同的作者,将中英文逗号、中英文括号等内容都替换为英文分号“;”,用于区分国籍与作者。之后,使用将字符串按照斜杠来分割成一个字符串数组,数组中每个字符串代表一个可能带有国家信息的作者名称,使用正则表达式:”^(;([\u4e00-\u9fa5]+);)?([\w\u4e00-\u9fa5\.•]+)”来匹配,取出可能以分号加中文字符开头的,作为国籍,以英文字符或者中文字符组成的连续的词作为作者姓名。
    之后,拿国籍信息去国籍信息表中查询,没有此项,则作为一个新的条目插入,有则不做处理。在有的数据清洗过程中,比如标签,它有一个统计数据,那么如果表中有这个标签,会将统计数据增加一个。作者姓名与国籍类似,采用相同的方法来存储。之后便查询下一条图书记录。

    为了加快读取速度,每次的读取并不只是一条,而是多条图书数据一起读取出来,这样会一次将较多的数据调入内存,降低磁盘IO操作,加快速度。可是由于每本书有三到五个作者,每个作者和国籍都会在解析出来之后变为一个独立的需要插入到数据库中或者去数据库中查询的条目,随着数据条数的增多,同时提交的事务数量会加倍增长,MySQL系统就出现了session数量不足的错误。于是,将每次取出的条数减少,并且在每次操作完成一组数据后,提交并关闭数据库,在需要操作前,再打开数据库。这样就能够即时的关闭用完的session,不会出现由于大量已结束的事务占用session而报错的问题。
    同样为了加快数据清洗速度,使用两台电脑,一台运行数据库系统,另一台运行Java程序,MySQL系统打开网络用户的访问权限和所在系统的防火墙3306端口,另一台连接并处理数据。由于数据库操作占比较大的时间,所以瓶颈依旧在运行数据库的系统中,不过相对与在同一个系统中,CPU占用和内存占用有一定程度的下降。
    4.3 系统开发按照总体设计阶段的分层,将系统分为三个包:cn.edu.ustb.controller、cn.edu.ustb.dm、cn.edu.ustb.model。如图4.6所示。

    4.3.1 控制器类controller包为系统结构中的controller模块,根据功能,划分为了五个类:BookInfoController.java负责图书详细信息的展示,IndexController.java负责首页的视图内容获取展示,LoginController.java负责登录信息的处理,RegisterListController.java负责对注册信息的处理,ResultListController.java负责处理查询。
    controller类将SqlSessionFactory使用注解的方式注入类中,并且使用注解来实现Controller类与请求映射。使用Log4j工具来输出日志。借鉴Objective-C的方式,使用setter/getter方法来获取变量,以便延迟加载以及提高利用率。代码结构如图4.7所示。

    在最开始,Mapper都是使用注解来注入进来的,但是发现SqlSession的开启与关闭不受到控制,完全靠系统来自动完成,那么在并发数量过大之后,大量线程占用session,很容易出现session数量过多的问题,其他人访问不了网站。将Mapper的获取方法改为了使用SqlSession的getMapper方法来获取,这样就可以完全控制session开启时间、结束时间。在每次访问页面的时候,包括浏览器会话没有关闭时刷新,都会重新开启一个新的SqlSession,获取新的Mapper实例,然后执行数据库操作,最后,关闭数据库连接。这样,能够即时的回收过期的SqlSession,防止大量无用的session占用数据库资源。
    在使用getter/setter方法时,刚开始将SqlSession的获取放到了getter中,这样会首先检测有没有实例,没有实例再创建,意图是为了延迟加载,在用到的地方才初始化它,并且防止每次使用都创建新实例。可是在实际中却发现,如果用户刷新页面,或者点击分页按钮,系统会抛出错误,说数据库已关闭,无法执行查询操作。原来每次访问,在浏览器没有结束会话时,Web容器会将Controller类的实例保存在内存中,而每次请求只会执行RequestMapping所指定的函数。于是修改SqlSession的获取方式,在浏览器每次发起请求时,通过SqlSessionFactory类的openSession函数来获取一个SqlSession实例。
    Mapper的获取也受到了影响,因为每次访问都会创建一个新的SqlSession实例,那么Mapper如果不为null的话,就不会重新创建Mapper实例,这样,Mapper的SqlSession将是已经关闭的session,它不能够执行任何数据库操作。因此,在每次访问时,会将所有的Mapper都重置为null,以使其重新初始化。
    4.3.2 模块类模块类包含一些页面需要的数据结构,对数据的加工函数以及分页功能实现。其中,BookClassifyItemModel.java类为单纯的书籍按照分类来显示信息的模块,其中,借鉴了MyBatis的Example类的方法,添加了一个内部类,在父类中编写了创建内部类的函数,用于创建图书列表。
    BookListItemModel.java类为图书的基本信息展示类,用在了图书推荐、图书排行、查询结果展示以及图书详细信息中。在类中提供了计算得分的函数,以及格式化日期的函数,用于在页面中显示。
    SearchResultPaginationModel.java类为查询结果分页模块,用于支持查询的分页显示以及分页功能。由于数据量巨大,为了提高查询效率,分页查询并没有采用MyBatis的分页查询方法,MyBatis会在第一次查询时,将所有的符合条件的结果读入内存中,之后再根据分页条件来显示,这样,虽然会在页面跳转的时候很快,但在第一次查询时,会有大量的磁盘IO操作,在数据类大的情况下,会对系统性能造成很大的影响,而搜索结果大部分用户只是关注前几页,后面的结果访问量并不大,这样就有些得不偿失。分页查询采用数据库的limit条件,只在每次查询时获取每一页要显示的数据,在创建了索引以后,这个查询过程是非常迅速的,只将需要的数据读入内存。查询效率提高了,就需要自己来实现分页。
    4.3.3 视图类视图使用jsp作为页面,引入了JSTL的c库来辅助生成布局。视图文件如图4.8所示。

    header.jsp为页面顶端的logo、搜索栏与登录注册按钮的部分。footer.jsp为页面底部版权信息的内容。pagination.jsp为分页,根据SearchResultPaginationModel.java的内容来生成分页。
    bookInfo.jsp负责显示图书的详细内容,index.jsp负责首页内容的显示,login和register负责登录与注册页面,resultList为搜索结果,只是单纯的搜索结果列表,用于分页时,通过AJAX请求来局部刷新,减少流量。resultListPag为搜索结果页面,是页面的框架,其中引入了resultList,作为第一次访问时,搜索结果的展示。
    每个页面都引入header.jsp与footer.jsp,用来引入所需要的布局文件与页面脚本,构建起基本的页面框架。页面导航栏的布局采用Bootstrap的导航栏样式,登录可以从导航栏上直接输入来登录。搜索条件分为标题、作者、出版社,可以对这三者进行查询。
    采用JSTL的标准c标签库,方便的实现循环(c:forEach)、判断(c:if、c:when),
    页面整体布局采用Bootstrap的响应式布局,首页、搜索结果页将正文部分分为左右两块,图书信息页面只有一个块。在首页中各个块中,每本书作为一个row类型,每个row又分为两个span,用于分割左右两块。一部分布局是由自定义的main.css文件来定制。而自定义的JavaScript也由在footer中引入的main.js来定制那些比如搜索按钮点击事件、分页按钮点击事件、登录等等。
    分页按钮的样式采用了Bootstrap的分页按钮,参考Amazon查询结果的分页效果,在页数多于9页的情况下,翻到中部,则只显示部分挨着的页码,结合SearchResultPaginationModel类的结构,完成了查询的分页。
    4.4 分析及调优首页为所有页面中最为复杂的页面,需要查询四块内容,页面效果如图4.9所示。

    四块内容分别需要按照各自的查询条件来排序,然后取前几个符合条件的结果。在刚开始,没有对数据库优化之前,页面打开速度几乎需要3秒,对查询SQL进行分析,发现,大部分操作时间都消耗在了排序上,于是对排序条件创建了索引,首页的首次打开延迟变得小于1秒,并且由于在控制器中使用getter\setter,部分没有参数的数据会在查询之后一直留在内存中,不会进行第二次查询,所以刷新会返回304,页面内容没有改变。

    图4.10为查询结果页面。由于此平台不涉及搜索算法的研究,所以搜索结果为从数据库字符串中like出来的。考虑到数据库巨大,若不做处理,将会严重影响查询效率。于是按照查询特点,对图书标题、出版日期两列做了索引,查询速度有了成倍的提升。再加上每次查询使用limit,磁盘内存间的交换操作减少了许多。

    图4.11为图书信息的展示页面,对图书的缩略图、内容以及作者简介做了展示,还有登录失败后会跳转到的登录页面,注册按钮点击后跳转到的注册页面,相对于其它两个相对功能较单一,性能也没有太大的提升空间。
    4.5 性能测试使用Chrome浏览器的开发者工具来进行测试。结果如图4.12所示,首次加载首页需要等待6ms,其它静态的css与js文件几乎不需要时间,在统计结果中,显示为0。之后刷新,Tomcat会从内存中直接取得返回结果,统计如图4.13所示,由图可知,加载页面仅需要用时2ms。

    在查询结果页面,查询一个关键词“IOS”,页面的等待时间为223ms。同样由于缓存的作用,刷新的等待时长变为8ms。结果如图4.14与4.15所示。

    4.6 小结本章介绍了整个系统的每个模块的整体设计、详细设计以及实现方式。并进行了简单的分析以及性能的调优,最终系统运行性能良好,稳定,系统结构简洁,功能完善。
    结 论随着计算机网络技术的发展,越来越多的电子商务网站、图书分析网站以及一些图书馆系统都采用了图书推荐系统这种智能化的解决方案,它有效的实践了长尾理论,增加了用户粘性。
    本文对基于Web的图书推荐系统的展示平台做了初步研究,开发了一个平台,开发过程包括网站数据库设计、数据清洗、系统结构设计、系统搭建、版本控制、性能调优等,功能模块包括图书展示、图书搜索、图书推荐、用户登录注册等,还对设计的过程、网站的结构、项目的管理方法进行了探索,对项目中遇到的难点给出了一些解决方案,起到的效果也比较不错。
    研究的核心部分是系统的设计与工具的使用。由于系统开发采用MVC结构,系统各个层级与模块之间的关系以及数据库结构,都需要一个具有高扩展性和可复用的设计,否则在开发后期或是在后期维护阶段,都会因为工程大小的增长而带来耦合性的急剧上升,最终导致功能实现与错误修改变得异常艰难。一些开源的开发框架与项目管理工具在系统开发过程中会极大地减轻开发者浪费在无关事务上的工作量,开发者不需要去操心布局怎样实现才能美观,怎样达到浏览器兼容,以及怎样去管理版本,控制查看进度,去哪里下载依赖包,项目需要哪些依赖,依赖包怎样升级等等。工具也可以减少开发者的重复劳动,比如MyBatis Generator可以自动生成单表操作的Mapper文件。
    开发中的难点是数据的清洗过程与数据库查询效率的优化。数据的清洗过程需要读取出记录后,对数据解析、去新表查询,根据查询结果插入到新表或者更新新表。操作比较复杂,由于数据的格式极不规整,在解析时,花了许多时间研究数据的格式的可能性,编写代码去除干扰数据,并用正则表达式解析它。一开始数据查询效率极低,在分析了SQL查询语句之后,对数据相应字段创建了索引,才使得数据查询的速度符合期望,解决了查询的效率问题。
    参考文献[1]项亮,陈义,王益著.推荐系统实践[M].北京:人民邮电出版社,2012.
    [2]Vincent, L.Google Book Search: DocumentUnderstanding on a Massive Scale[J].Document Analysis and Recognition,2007: 819 - 823
    [3]裴玉洁著.采用数据挖掘技术的自动化推荐系统的研究[D].2012.
    [4]吴定勇,王峰著.亚马逊书店的网络售书之道[J].北京:当代传播,2008, (6): 123-125.
    [5]李连焕,刘建东著.基于Web日志挖掘的图书借阅推荐算法研究[J].北京:硅谷,2012,(6): 93-94.
    [6]古丽拜天.卡米尔著.基于Web数据挖掘的智能推荐研究[D].湖南:中南大学,2010.
    [7]李俊杰著.Maven在企业Java软件产品中的应用[D].北京:北京邮电大学,2011.
    [8]刘悦之著.基于Git的分布式版本控制系统的设计与实现[D].上海:同济大学,2012.
    [9]张琛,吴跃,邱会中著.基于Structs+Spring+Hibernate的整合架构及其在电信业中的应用[D].四川成都:电子科技大学,2006.
    [10]陆荣幸,郁洲,阮永良,王志强著.J2EE平台上MVC设计模式的研究与实现[J].计算机应用研究,2003, 20(3): 144-146.
    [11]Praveen Gupta, Prof. M.C. Govil. MVC DesignPattern for the multi framework distributed applications using XML, spring andstruts framework[J].International Journal on Computer Science and Engineering,2010, 2(4):1047-1051.
    [12]冯润民著.基于SSH的高校学生管理系统设计与实现[J].北京:计算机工程,2009, 35(6): 280-282.
    [13]DaveMinter,Jeff Linwood著.Hibernate基础教程[M].陈剑瓯等译.北京:人民邮电出版社,2008.
    [14]孙强,孙龙清,邱小彬著.基于Structs+Spring+iBATIS的轻量级Web应用框架研究[J].北京:计算机应用与软件,2008, 25(10): 135-137.
    [15]王庆民著.基于Web图书推荐系统设计[J].山西:晋图学刊,2011, (1): 35-37.
    [16]曾庆辉,邱玉辉著.一种基于协作过滤的电子图书推荐系统[J].北京:计算机科学,2005,32(6): 147-150.
    [17]张富国著.电子商务协同过滤推荐系统的研究与进展[D].江西:江西财经大学信息管理学院,2010.
    [18]田元,宋纬华,李婷婷著.基于Markov链的图书推荐系统的研究与设计[J].陕西:西安理工大学图书馆,2012, 32(6): 79-82.
    致 谢本课题是在指导老师的亲切关怀和悉心指导下完成的。老师对提交文档的细心浏览,总能挑出不合要求的地方,指导我改正。对我的毕设进度也一直很关心,提醒我按时提交。老师给予我很大帮助,在项目初期确定题目给我很大帮助。在此,谨向老师们表示由衷的感谢。
    另外,要感谢学姐、同学以及学弟,在项目初期,与老师一起讨论我的题目与内容,在整个毕设过程中,学姐对我提交的文档、论文以及整个毕设中一些注意事项为我提供指导意见。感谢同学,在我上班时间帮我打印、找老师签字以及提交文档,还有对我关于毕业一些疑问的解答。
    最后,感谢我使用的所有开源、自由软件的开发者们。你们无私的工作引导了各个领域的技术创新,改变了人们的生活方式。没有前人的工作,我不可能完成这个课题,感谢你们,感谢所有关心、帮助过本课题的老师、同学们!
    7 评论 44 下载 2018-09-29 21:17:50 下载需要17点积分
  • 基于JAVA实现的Tiger编译器

    一、项目要求及完成情况
    正确的词法/语法分析,给出对应的文法文件
    输出正确的抽象语法树(testcases中50个测试文件,testcase-result中对应的抽象语法树)
    错误处理功能

    提示错误类型(词法错误、语法错误、语义错误等)、出错位置等(词法错误,语法错误ANTLR默认行为,部分语义错误:变量作用域及基本类型检查)错误修复(ANTLR默认行为 single-token insertion and single-token deletion)
    发挥想象力,使编译器尽善尽美(实现了变量作用域检查和基本类型检查)
    Project文档

    使用语法(文法类型,有无改动语法、如何改动等),错误处理说明等(对实现的变量作用变量作用域检查和基本类型检查的错误处理代码进行了介绍)对本项目语法的使用工具的体会(ANTLR简述部分)

    二、项目总览使用ANTLR工具,为Tiger构造一个编译器前端,将输入的Tigger语言转化为抽象语法树,实现了变量作用域检查和简单的Type Checking。
    三、ANTLR简述ANTLR(ANother Tool for language Recognition),作者Terence Parr(University of San Francisco)。
    ANTLR是一个可以接受含有语法描述的语言描述符并且生成程序能够识别这些语言所产生的句子。作为一个翻译程序的 一部分,你可以给你的语法附上简单的操作符和行为并且告诉ANTLR如何构造AST并且如何输出它们。ANTLR知道如何使用Java,C++,C#或者Python来生成它们。注意到词法错误和语法错误ANTLR有默认的处理行为。

    Here is how ANTLR uses those ideas together in a nutshell: parsers perform single-token insertion and single-token deletion upon mismatched token errors if possible. If not, parsers gobble up tokens until they find a token that could reasonably follow the current rule and then return, continuing as if nothing had happened.


    如上图所示,把源文件转化成AST,需要一个Lexer和Parser。Lexer把源文件读入,分成一个个token。然后Parser读入Lexer产生的token生成AST。在ANTLR提供了Lisenter和Visitor两种方式来遍历抽象语法树。本项目利用这些接口来实现变量声明检查。和基本的类型检查。

    四、AST的生成ANTLR是一个比较成熟的工具,The Definitive ANTLR 4 Reference 详细介绍了工具的使用说明。为了生成AST,需要完成grammer定义文件Tiger.g4 下面定义的语法,基本与官方语法文档指定的语法相同。 为了简化之后的Type Checking,把Ojbect相关的new class等语法去掉了。
    java org.antlr.v4.Tool Tiger.g4
    然后会产生TigerLexer.java, TigerParser.java, Tiger.tokens , TiegerLexder.tokens, TigerListener.java, TigerBaseLisetener.java。
    其中TigerLexer.java是ANTLR根据g4为我生成的Lexer,TigerParser.java是对应的Parser,TigerListener.java是前面提到的Listener方式的抽象语法树的接口,TigerBaseListener.java是这个接口的一个基本实现。我们的实现通过继承TigerBaseListener来重载中间的放来实现期望的行为。
    java org.antlr.v4.runtime.misc.TestRig Tiger program -tree test.in # 输出文本信息java org.antlr.v4.runtime.misc.TestRig Tiger program -gui test.in # 生成图形
    4.1 TigerLexer.java节选// Generated from Tiger.g4 by ANTLR 4.2.1import org.antlr.v4.runtime.Lexer;import org.antlr.v4.runtime.CharStream;import org.antlr.v4.runtime.Token;import org.antlr.v4.runtime.TokenStream;import org.antlr.v4.runtime.*;import org.antlr.v4.runtime.atn.*;import org.antlr.v4.runtime.dfa.DFA;import org.antlr.v4.runtime.misc.*;@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})public class TigerLexer extends Lexer { protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int T__39=1, T__38=2, T__37=3, T__36=4, T__35=5, T__34=6, T__33=7, T__32=8, T__31=9, T__30=10, T__29=11, T__28=12, T__27=13, T__26=14, T__25=15, T__24=16, T__23=17, T__22=18, T__21=19, T__20=20, T__19=21, T__18=22, T__17=23, T__16=24, T__15=25, T__14=26, T__13=27, T__12=28, T__11=29, T__10=30, T__9=31, T__8=32, T__7=33, T__6=34, T__5=35, T__4=36, T__3=37, T__2=38, T__1=39, T__0=40, INTEGER=41, STRING=42, ID=43, COMMENT=44, LINE_COMMENT=45, WS=46; public static String[] modeNames = { "DEFAULT_MODE" };...
    4.2 TigerParser.java节选// Generated from Tiger.g4 by ANTLR 4.2.1import org.antlr.v4.runtime.atn.*;import org.antlr.v4.runtime.dfa.DFA;import org.antlr.v4.runtime.*;import org.antlr.v4.runtime.misc.*;import org.antlr.v4.runtime.tree.*;import java.util.List;import java.util.Iterator;import java.util.ArrayList;@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"})public class TigerParser extends Parser { protected static final DFA[] _decisionToDFA; protected static final PredictionContextCache _sharedContextCache = new PredictionContextCache(); public static final int T__39=1, T__38=2, T__37=3, T__36=4, T__35=5, T__34=6, T__33=7, T__32=8, T__31=9, T__30=10, T__29=11, T__28=12, T__27=13, T__26=14, T__25=15, T__24=16, T__23=17, T__22=18, T__21=19, T__20=20, T__19=21, T__18=22, T__17=23, T__16=24, T__15=25, T__14=26, T__13=27, T__12=28, T__11=29, T__10=30, T__9=31, T__8=32, T__7=33, T__6=34, T__5=35, T__4=36, T__3=37, T__2=38, T__1=39, T__0=40, INTEGER=41, STRING=42, ID=43, COMMENT=44, LINE_COMMENT=45, WS=46; public static final String[] tokenNames = { "<INVALID>", "']'", "'&'", "'in'", "'of'", "','", "'['", "'-'", "'*'", "'while'", "'('", "':'", "'<'", "'<='", "'var'", "'array'", "'nil'", "'to'", "'{'", "'break'", "'let'", "'else'", "'}'", "'do'", "')'", "'function'", "'.'", "'+'", "'for'", "'<>'", "'='", "';'", "'if '", "'>'", "'type'", "':='", "'then'", "'/'", "'>='", "'|'", "'end'", "INTEGER", "STRING", "ID", "COMMENT", "LINE_COMMENT", "WS" };...
    4.3 Tiger.g4语法文件/** May,28 2014 author: whimsycwd compiler project*/grammar Tiger;program : exp | decs ;exp : 'nil' #Nil | INTEGER #Integer | STRING #String | type_id '[' exp ']' 'of' exp #Array | type_id '{' ( ID '=' exp (',' ID '=' exp )* )? '}' #Record //| 'new' type_id #New | lvalue #LeftValue | ID '(' ( exp (',' exp)*)? ')' #Call | '-' exp #UnaryMinus | exp ('*' | '/') exp #Mul | exp ('+' | '-') exp #Add | exp ('<>' | '=' | '>=' | '<=' | '>' | '<') exp #Cmp | exp ('&' | '|') exp #Logical | '(' exps ')' #ParenExprs | lvalue ':=' exp #Assign | 'if ' exp 'then' exp ('else' exp)? #IfStmt | 'while' exp 'do' exp #WhileStmt | 'for' ID ':=' exp 'to' exp 'do' exp #ForStmt | 'break' #Break | 'let' decs 'in' exps 'end' #LET ;exps : ( exp (';' exp)* )?; decs : dec*; dec : 'type' ID '=' ty #TypeDec | vardec #VarDecNothing | 'function' ID '(' tyfields? ')' (':' type_id)? '=' exp #FuncDec //| 'primitive' ID '(' tyfields? ')' (':' type_id)? //| 'import' STRING //| 'class' ID ('extends' type_id)? '{' classfields '}' ;vardec : 'var' ID (':' type_id)? ':=' exp #VarDecInner ;//classfields : classfield*// ;//classfield : vardec// | 'method' ID '(' tyfields ')' (':' type_id) '=' exp// ;ty : type_id | '{' tyfields? '}' | 'array' 'of' type_id// | 'class' ('extends' type_id)? '{' classfields '}' ;tyfields : ( ID ':' type_id (',' ID ':' type_id)*);type_id : ID;lvalue : ID #SimpleVar | lvalue '.' ID #DotVar | lvalue '[' exp ']' #BracketVar ;INTEGER : DIGIT+;STRING : '"' (ESC | .)*? '"';ID : LETTER (LETTER | DIGIT) *;fragmentESC : '\\' [btnr"\\];fragmentLETTER : [a-zA-Z] | '_';fragment DIGIT : [0-9];COMMENT : '/*' .*? '*/' ->skip;LINE_COMMENT : '//' .*? '\n' ->skip;WS : [ \n\r\t]+ ->skip;五、AST测试5.1 配置测试环境 config.profileBASE="/Users/whimsycwd/Repo/ANTLR/Tiger/"export CLASSPATH=".:./lib/antlr-4.2.1-complete.jar:${BASE}lib/antlr-4.2.1-complete.jar:${BASE}classes"alias antlr4='java org.antlr.v4.Tool'alias grun='java org.antlr.v4.runtime.misc.TestRig'alias runTiger='grun Tiger program'
    上述代码为Terminal配置了环境变量。只需改变BASE到实际的地址。在Terminal中source config.profile,就可以使用antlr4,grun,runTiger的指令的简称。
    5.2 下载测试代码 fetch.shURL=http://www.computing.dcu.ie/~hamilton/teaching/CA448/testcases/rm *.tigfor i in {1..49}do curl -O "${URL}test${i}.tig"donefor name in 'queens.tig' 'merge.tig'do curl -O "${URL}$name"done新建文件夹testcases, 在该目录下执行上述的代码可以将测试文件批量下载下来。
    5.3 编译运行 run.sh# clean the generated file and recompile# May 31,2014 whimsycwd#source config.profilerm Tiger*.java 2>/dev/null#rm Tiger*.class 2>/dev/nullrm Tiger*.tokens 2>/dev/nullrm ./classes/* 2>/dev/nullecho "File deleted"echo "ANTLR Generating"java org.antlr.v4.Tool Tiger.g4echo "Compile Start"#javac Tiger*.java -d ./classes/javac *.java -d ./classes/
    5.4 输出测试AST结果 runAllTest.sh# RUN ALL TEST# May 31, 2014 whimsycwdecho "deleting testcases-result"rm testcases-result/*for i in {1..49}do echo "test${i}.tig is processing" java org.antlr.v4.runtime.misc.TestRig Tiger program -tree "testcases/test${i}.tig" > "testcases-result/test${i}.tig.res"donefor name in 'queens.tig' 'merge.tig'do echo "${name} is processing" java org.antlr.v4.runtime.misc.TestRig Tiger program -tree "testcases/${name}" > "testcases-result/${name}.res"done
    新建testcases-result,利用上述代码能够批量输出测试代码到testcases-result/。
    5.5 结果示例 1 testcases/test1.tig/* an array type and an array variable */let type arrtype = array of int var arr1:arrtype := arrtype [10] of 0in arr1end代码输出了AST结果文件:testcases-result/test.tig.res。
    (program (exp let (decs (dec type arrtype = (ty array of (type_id int))) (dec (vardec var arr1 : (type_id arrtype) := (exp (type_id arrtype) [ (exp 10) ] of (exp 0))))) in (exps (exp (lvalue arr1))) end))对应的图形化的结果为:

    5.6 结果示例 2 mytest/error.in 错误提示和行号let var a:== 1 var b:= 2in let var c := 3 in d endend代码输出结果
    whimsyMini:Tiger whimsycwd$ runTiger -tree error.inline 2:11 no viable alternative at input '='(program (exp let (decs (dec (vardec var a := (exp = 1))) (dec (vardec var b := (exp 2)))) in (exps (exp let (decs (dec (vardec var c := (exp 3)))) in (exps (exp (lvalue d))) end)) end))对应的图形化的结果,追到错误的地方,被高亮出来了,并且跳过继续解析。

    六、变量作用域检查为了实现变量声明的检查,两次遍历抽象语法树,第一次遍历抽象语法树,简历变量表,注意在遍历的过程中,还要考虑作用域,进入一个作用域的时候需要创建新的作用域。作用域构成一个链表,resolve一个变量的时候需要跟往上层去查找。
    6.1 CheckSymbols.java...public void process(String[] args) throws Exception { String inputFile = null; if ( args.length>0 ) inputFile = args[0]; InputStream is = System.in; if ( inputFile!=null ) { is = new FileInputStream(inputFile); } ANTLRInputStream input = new ANTLRInputStream(is); TigerLexer lexer = new TigerLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); TigerParser parser = new TigerParser(tokens); parser.setBuildParseTree(true); ParseTree tree = parser.program(); ParseTreeWalker walker = new ParseTreeWalker(); DefPhase def = new DefPhase(); walker.walk(def, tree); // create next phase and feed symbol table info from def to ref phase RefPhase ref = new RefPhase(def.globals, def.scopes); walker.walk(ref, tree);}...
    具体的代码 CheckSymbols.java、DefPhase.java、Scope.java、BaseScope.java、GlobalScope.java、LocalScope.java、RefPhase.java。
    第一阶段DefPhase,如下所示,比如在进入Function的时候currentScope = new LocalScope(currentScope); 新建一个作用域。在退出Function的时候 currentScope = currentScope.getEnclosingScope(); 往链表上层去找。
    6.2 DefPhase.java...public void enterFuncDec(TigerParser.FuncDecContext ctx){ currentScope = new LocalScope(currentScope); TigerParser.TyfieldsContext tyfields = ctx.tyfields(); if (tyfields != null){ List<TerminalNode> list = tyfields.ID(); for (TerminalNode e : list){ currentScope.define(new VariableSymbol( e.getSymbol().getText() ) ); // 把变量添加到当前作用域 } } saveScope(ctx, currentScope);}public void exitFuncDec(TigerParser.FuncDecContext ctx){ currentScope = currentScope.getEnclosingScope(); // 退出作用域}...
    检查变量varName是否在存在。解析变量代码如下。
    6.3 BaseScope.javapublic Symbol resolve(String name) { Symbol s = symbols.get(name); if ( s!=null ) return s; if ( enclosingScope != null ) return enclosingScope.resolve(name); return null; // not found}
    在第二阶段RefPhase当变量解析不到该变量,输出该类型的错误。
    6.4 RefPhase.java...public void exitSimpleVar(TigerParser.SimpleVarContext ctx){ String name = ctx.ID().getSymbol().getText(); Symbol var = currentScope.resolve(name); if (var == null){ CheckSymbols.error(ctx.ID().getSymbol(),"no such variable: " + name); } ...
    七、变量声明测试7.1 结果示例 mytest/test.inlet var a:= 1 var b:= 2in let var c := 3 in d endend注意到这个代码中 d并找不到此变量。可得到输出结果
    whimsyMini:Tiger whimsycwd$ java CheckSymbols mytest/test.inline 8:8 no such variable: d八、基本的类型检查为了实现基本的类型检查,对于每一个抽象语法树上的节点都需要给他一个类型。定义了一个AST节点到Type的映射typeSys.
    'for' ID ':=' exp 'to' exp 'do' exp下面的代检查了三个exp的类型。 exp1 和 exp2必须是Type.tInt。而对于整个语句的类型定义为exp3。
    RefPhase.java
    ... Type t1 = typeSys.get(ctx.exp(0)); Type t2 = typeSys.get(ctx.exp(1)); if (t1 != Type.tInt){ CheckSymbols.error( ctx.getStart(), "loop pd expression must be tInt" ); typeSys.put(ctx, Type.tVoid); } else { typeSys.put(ctx, t2); } print("In WhileStmt : " + typeSys.get(ctx) );}public void exitForStmt(TigerParser.ForStmtContext ctx){ Type t1 = typeSys.get(ctx.exp(0)); Type t2 = typeSys.get(ctx.exp(1)); Type t3 = typeSys.get(ctx.exp(2)); if (t1 != Type.tInt || t2 != Type.tInt){ CheckSymbols.error( ctx.getStart(), "loop start and end must both be tInt" ); typeSys.put(ctx, Type.tVoid); } else { typeSys.put(ctx, t3); } print("In ForStmt " + typeSys.get(ctx)); currentScope = currentScope.getEnclosingScope();}public void exitLET(TigerParser.LETContext ctx){ typeSys.put(ctx, typeSys.get( ctx.exps() ) ); currentScope = currentScope.getEnclosingScope(); // exit a scope print("In LET: "+typeSys.get(ctx) );}public void exitExps(TigerParser.ExpsContext ctx){ List<TigerParser.ExpContext> list = ctx.exp(); typeSys.put(ctx, typeSys.get( list.get(list.size() -1 ) ) ); print("In exps: "+ typeSys.get(ctx) );}...九、基本的类型检查测试结果示例 mytest/add.in
    1 let 2 var a := nil 3 var b := 12 4 var c := "adfaf" 5 var d := 133 6 in 7 -c; 8 -b; 9 b+d; 10 b-d; 11 a+c; 12 b/d; 13 b*d; 14 b*(d+b); 15 d := b+d 16 17 end这个代码的输出结果,发现了其类型的错误。注意到line 7 -c,其中c是一个String错误。line 11 a + c, 只有Int有定义 加法。
    whimsyMini:mytest whimsycwd$ java CheckSymbols add.inline 7:4 Expected - Int, got - tStringline 11:4 Expected Int +/- Int got tVoid +/- tString
    1 评论 1 下载 2019-05-05 15:10:37 下载需要11点积分
  • 基于JSP实现的试题库管理系统

    1 引言1.1 编写目的该需求分析报告用于软件开发小组对基于WEB的软件工程课程试题库管理系统这一课题的开发过程。明确了课题开发的目的与要求,介绍了该系统的所有功能以及适用范围。
    1.2 项目背景
    运行环境

    JDK1.7Tomcat7MySQL 5.6.11
    开发平台

    Windows 8.1 Pro(x64)MyEclipse10

    1.3 定义数据流图:数据流图描绘系统的逻辑模型,图中没有任何具体的物理元素,只是描绘信息在系统中流动和处理的情况。
    系统的流程图:系统流程图是描绘物理系统的传统工具。它的基本思想是用图形符号以黑盒子的形式描绘系统里的每个部件(程序,文件,数据库,表格,人工过程等)。
    学生表:学号,姓名,密码md5串,学院,班级id,手机号,邮箱,注册时间
    教师表:职工号,教师姓名,密码md5串,学院,手机,邮箱,注册时间
    班级表:班级id,学院,班级名称,创建教师id
    题库表:试题id,试题名称,试题内容,试题答案,试题类型,试题所有者id,添加时间,4个额外备注信息
    试卷表:试卷id,试卷名称,试卷创建者id,创建试卷时间,试卷目的班级id
    答卷表:学生id,试卷id,学生在该份试卷的得分
    组题表:试卷id,试题id,该道试题在该试卷的分值
    1.4 参考资料
    《软件工程》 钱秋乐,清华大学出版社,2007
    《数据库系统开发》 文东,北京科海电子出版社,2009
    《JavaWeb整合开发王者归来》
    《Java程序设计》
    《JSP从入门到精通》
    《Think in Java》

    2 概要设计由于软件实际实现的功能有限,只实现了学生/教师注册登录模块,学生考试功能以及教师增加、删除、修改试题的功能。
    2.1 三层架构总业务流程图
    2.2 总体概要本系统采用三层架构进行设计,层与层之间采用Java接口进行衔接,降低了模块耦合度,并使用工厂模式实现对不同需求对应接口的不同实现,并在每一层功能完成后进行相应层的单元测试,对开发过程中避免了很多不必要的麻烦,节约了开发时间。
    本系统在开发过程中实现了国际化框架,可以识别不同的浏览器语言相应的显示对应语言的内容,由于开发时间限制,语言包只提供了缺省的中文语言包。
    表示层:该系统对每个表单设置表单号和验证码,可以有效防止用户的表单重复提交。本系统参考了Struct框架的表单Bean检验方式,对用户输入的表单信息进行了相应的约束,并使用正则表达式进行校验,对于不符合约束的信息,及时在网页上回显给用户,只对符合要求的表单信息提交给下层Service业务处理层,保证了业务处理层接收到的表单信息的纯净性。业务处理层:对本系统需要提供的功能进行封装和分类,分成StudentService,TeacherService和QuestionService三个子系统。
    持久层:持久层对应业务处理层,也分成了StudentDao,TeacherDao,QuestionDao三个子系统。持久层对MySQL的数据库操作进行了实现,数据库连接信息以配置文件的形式存放在网站目录中,增强了系统的灵活性,对于更改数据库只需更改相应的配置文件即可,并对Dao接口对应相应数据库进行实现即可。
    2.3 类包层次结构图
    主包名

    com.silence.questionlib
    子包

    dao:持久层接口,其中有三个接口,分别是学生子系统,教师子系统,题库子系统的对应持久层接口
    daoimpl:持久层接口实现类,分别实现持久层接口中的三个接口
    domain:整个系统的所有实体JavaBean
    exception:自定义异常
    factory:工厂模式工厂包,工厂遵循单例模式,实现根据不同的需要加载对接口的不同实现类,通过Java类加载器实现,从配置文件factory.properties读取相应的类加载信息
    formbean:用户提交表单JavaBean,实现对表单校验和相应的用户反馈信息生成,反馈信息实现国际化
    i18n:国家化包,实现国际化的工具类和相应的国际化语言包
    service:业务处理层接口,分为学生子系统,教师子系统,题库子系统三个业务处理接口
    serviceimpl:业务处理层接口对应的实现类,分别实现业务处理层的三个接口
    utils:整个项目的所有工具类,包括每个层的对应工具类
    web.controller:表示层控制型Servlet,实现对用户业务处理请求的初步处理和对业务处理层的请求
    web.ui:表示层显示型Servlet,实现对用户的请求预处理和过滤,并转发到JSP页面
    junit.test:测试包
    db.properties:JDBC连接数据库的相关配置信息
    factory.properties:工厂模式加载相应实现类的映射文件

    2.4 网站根目录层次结构图

    images:网站图片文件夹
    temp:网站缓存文件夹
    jsp:网站JSP文件夹
    lib:网站引用jar包文件夹
    tag.tld:自定义标签库描述文件
    web.xml:网站配置文件
    index.jsp:网站首页
    message.jsp:网站全局信息显示页面

    2.5 用户请求表单处理流程
    3 详细设计3.1 各个包中类详细说明
    Com.silence.questionlib.dao

    QuestionDao:试题操作持久层接口,对试题的增删改查,组卷等功能StudentDao:学生操作持久层接口,学生登录注册等基本功能TeacherDao:教师操作持久层接口,教师注册登录,创建班级,查看班级学生等功能
    Com.silence.questionlib.daoimp

    QuestionDaoimpl:试题操作持久层实现StudentDaoimpl:学生操作持久层实现TeacherDaoimpl:教师操作持久层实现JdbcUtil.java:JDBC操作工具类
    Com.silence.questionlib.domain

    Group:班级实体,对应班级表Paper:试卷实体,对应试卷表Question:试题试题,对应试题表Result:验证码生成结果实体Student:学生实体,对应学生表Teacher:教师实体,对应教师表
    Com.silence.questionlib.domain. exception

    DaoException:持久层未知异常GroupNotExist:班级不存在异常PaperNotExist:试卷不存在异常QuestionNotExist:试题不存在异常QuestionUsedException:试题正在被试卷使用异常ServiceException:业务处理层未知异常StudentNotExist:学生不存在异常TeacherNotExist:教师不存在异常
    Com.silence.questionlib.domain. factory

    DaoFactory:持久层连接工厂,根据配置文件实现对不同持久层实现的相应加载
    Com.silence.questionlib.domain. fombean

    QuestionForm::添加和修改试题表单Bean,进行表达校验和错误信息合成StudentLoginForm:学生登录表单Bean,进行表达校验和错误信息合成StudentRegisterForm:学生注册表单Bean,进行表达校验和错误信息合成TeacherLoginForm:教师登录表单Bean,进行表达校验和错误信息合成TeacherRegisterForm:教师注册表单Bean,进行表达校验和错误信息合成
    Com.silence.questionlib.domain. i18n

    I18nTag:自定义国际化标签I18nUtils:国际化工具类resource.properties:国际化资源文件的缺省文件
    Com.silence.questionlib.domain. service

    QuestionLibService:试题操作业务处理接口,对试题的增删改查,生成试卷等业务操作StudentService:学生业务处理接口,实现对学生登录注册,查看试卷等学生业务操作TeacherService:教师业务处理接口,实现对教师注册登录,创建班级,查看班级学生等业务操作
    Com.silence.questionlib.domain. serviceimpl

    QuestionLibServiceImpl:试题操作业务实现类StudentServiceImpl:学生业务处理实现类TeacherServiceImpl:教师业务处理实现类
    Com.silence.questionlib.domain. utils

    ServiceUtils:业务处理层工具类WebUtils:表示层工具类
    Com.silence.questionlib.domain. web. controller

    AddPaperServlet:处理教师添加试卷请求操作AddQuestionServlet:处理教师添加试题请求操作CheckServlet:处理学生提交试卷之后的批改操作DeleteQuestionServlet:处理教师删除试题的请求操作GroupServlet:处理教师查看班级学生的请求操作ListQuestionServlet:处理教师查看题库的请求操作LoginServlet:处理学生教师的登录请求操作PaperServlet:处理学生查看试卷的请求操作QuestionDetailServlet:处理教师查看题库中详细试题信息的请求操作RegisterServlet:处理学生教师注册请求操作UpdateQuestionServlet:处理教师修改试题信息的请求操作
    Com.silence.questionlib.domain. web. ui

    AddPaperUIServlet:向教师返回创建试卷的界面AddQuestionUIServlet:向教师返回添加试题的界面LoginUIServlet:返回学生教师的登陆请求界面RegisterUIServlet:返回学生教师的注册界面UpdateQuestionUIServlet:返回教师修改试题的界面

    3.2 登陆验证模块说明3.2.1 程序描述本系统的所有功能模按块都必须调用“登录验证”子模块进行身份验证,此模块是所有用户进入系统时都必须调用的模块,系统用户登录界面中的【登录】按钮触发。
    学生和教师的登录入口分开单独管理,以进入不同的界面,被赋予不同的特权。
    进行登录界面时,需要输入账号、密码、验证码等信息均正确的情况下方可进入。
    验证码是从0-09数字与a-z大小写字母组成,随机生成验证码图片,并保存到服务器会话对象中,因此验证码有时间期限。
    3.2.2 功能登录验证功能模块的IPO表如下表所示:

    3.2.3 界面

    3.2.4算法【登录】按钮触发的处理:验证用户的合法性。
    处理流程

    取得用户输入的用户名、密码和验证码
    加密用户名和密码传输到数据库并与帐户表进行一致性验证
    如果用户名、密码和验证码都正确,以该用户身份进入系统总控制界面并获得相应系统权限,否则根据某项错误提示对应的错误信息,如:不存在该账号、密码错误、验证码错误、账号不能为空

    3.2.5 流程逻辑
    3.2.6 接口本模块是系统的启动模块,它需要用户交互输入用户帐号、密码;它调用主控制模块。
    3.2.7 限制条件预先设置一个管理员和一个用户。
    3.2.8 测试计划
    初次安装系统后,测试初始用户帐号和密码能否正确登录到系统
    正确登录后,退出注册一个新的账号
    采用刚注册的用户账号和密码登录,应该能够正确登录
    将某一项不填看是否提示错误信息
    将某一项填错查看错误信息

    3.3 注册模块说明3.3.1 程序描述对于没有账号的学生或教师,需要注册后才可以使用本系统。学生和教师因为输入信息不同,所以分为两个入口,进入注册界面后,需要输入相应的信息,并且这些信息符合规范才可以注册成功。将注册成功后的信息加入到对应的数据库表中。
    点击注册,则注册完成。
    3.3.2 功能注册模块的IPO表如下表所示:

    3.3.3 界面
    3.3.4 算法点击注册按钮,检测输入的合法性。
    处理流程

    输入注册界面的所有内容
    点击注册,检测输入的合法性
    如果不合法提示错误信息,如果合法则显示注册成功

    注册时,账号和密码均采用MD5进行加密,将加密后的账号和密码保存到相应表的数据库中,以增加账户的安全性。
    3.3.5 流程逻辑
    3.3.6 接口当所有信息填写均符合规范,并点击注册时,所有相应信息会保存到相应数据表中。并提示注册成功。
    3.3.7 限制条件只有所有信息都符合限制规范才可以注册成功。
    3.3.8 测试计划
    进行多次注册尝试,经注册后的信息进行登录,看是否会提示错误
    输入不符合规范的信息,看是否会提示相应错误

    3.3.9 尚未解决的问题注册成功后没有跳到主页。
    3.4 教师管理试题库系统3.4.1 程序描述本系统的所有功能模按块都必须调用“登录验证”子模块进行身份验证,此模块是所有用户进入系统时都必须调用的模块,而在验证的过程中除了要输入教师的职工号和密码外,同时还要输入验证码,让后方可通过系统用户登录界面中的【登录】按钮触发。如果错误,则显示错误的原因,比如验证码错误,如果正确的话则进入页面。接下来我们在教师的的管理界面里面可以看到有各种试题库,教师可以根据需要在里面增加试题,修改试题,删除试题,也可以重新加入一套试卷,或者删除一套试卷,同时我们也可以对试题库里面的题目进行查看,例如时间,出题人,也可以看到做题人(及学生)的班级和信息。
    3.4.2 功能登录验证功能模块的IPO表如下表所示:

    3.4.3 界面





    3.4.4 算法
    【试题修改】按钮触发的处理:进入试题修改界面;如果进行修改试题信息并确定,便对试题表中的试题信息进行修改
    【试题添加】按钮触发的处理:进入试题修改界面;如果进行添加试题信息并确定,便对试题表中的试题信息进行添加
    【试题删除】按钮触发的处理:进入试题删除界面;如果进行删除试题信息并确定,便对试题表中的试题信息进行删除
    【试卷添加】按钮触发的处理:进入试卷添加界面;如果进行添加试卷信息并确定,便对试卷表中的试卷信息进行添加
    【试卷删除】按钮触发的处理:进入试卷删除界面;如果进行删除试卷信息并确定,便对试卷表中的试卷信息进行删除
    【试卷修改】按钮触发的处理:进入试卷修改界面;如果进行修改试卷信息并确定,便对试卷表中的试卷信息进行修改
    【班级信息】按钮触发的处理:进入班级信息界面;如果进入班级信息并确定,便进入班级信息
    【试题信息】按钮触发的处理:进入试题信息界面;如果进入试题信息并确定,便进入试题信息
    【返回】返回上一层界面

    3.4.5 流程逻辑
    3.4.6 接口本模块是系统的主要输入模块模块,他需要老师成功登陆后方可进行,老师对系统的操作,将改变相应的数据库内容。
    3.4.7 限制条件至少有一名教师,以及一套试卷,试卷里面有一道题。
    3.4.8 测试计划
    初次安装系统后,测试是否可以进入教师管理试题库里面
    进入之后,查看是否可以进行试题的添加删除修改的操作,以及对试卷的添加删除修改的操作,和对班级信息的查看,以及学生的信息的查看,还有试题的信息的查看

    3.4.9 尚未解决的问题未能从其他的数据库内导入试卷和试题。
    3.5 学生考试系统3.5.1程序描述本系统的所有功能模按块都必须调用“登录验证”子模块进行身份验证,此模块是所有用户进入系统时都必须调用的模块,而在验证的过程中除了要输入学生的职工号和密码外,同时还要输入验证码,让后方可通过系统用户登录界面中的【登录】按钮触发。如果错误,则显示错误的原因,比如验证码错误,如果正确的话则进入页面。接下来我们在学生考试的管理界面里面可以看到有各种试题,学生可以根据试题选择其中的一套进行填写,填写完后可以进行提交。
    3.5.2 功能学生考试功能模块的IPO表如下表所示:

    3.5.3 界面



    3.5.4 算法点击相应试题,进入做题界面。
    处理流程

    点击相应试题进入做题界面
    填写试卷内容
    填写完试卷内容后,点击提交 ,返回界面

    3.5.5 流程逻辑
    3.5.6 接口本模块是系统的学生考试模块,需要学生成功登陆后方可使用。通过提交试题更改相应的数据库。
    3.5.7 限制条件至少有一名学生,以及一套试卷,试卷里面有一道题。
    3.5.8 测试计划
    选择多份试卷进行填写并提交,看能否提交成功
    不同的账号登陆进行填写试卷提交

    3.5.9 尚未解决的问题试卷复查,试卷批改尚未完成。
    1 评论 86 下载 2018-11-06 10:17:49 下载需要5点积分
  • Linux环境下的UDP端口扫描程序

    一、开发目的UDP扫描扩展实现
    二、系统功能在命令行模式下实现对连续UDP端口的扫描。
    三、系统设计3.1 系统的组成结构
    主函数。函数原型为:
    int main(int argc,char \*argv[])
    该函数为主函数,控制整个工具的运行流程
    命令行解析函数。函数原型为:
    int parse_scanpara(int argc, char *argv[],struct scaninfo_struct *pparse_result)
    该函数被主函数调用,主函数直接将命令行输入以函数参数形式传递给该函数,该函数解析命令行函数,将解析结果保存在参数pparse_result指向的scaninfo_struct的结构体中。
    UDP扫描函数。该函数原型为:
    void udp_scan(struct scaninfo_struct *pscaninfo)
    该函数由主函数调用,以发送UDP报文,捕获分析ICMP报文的的方式来探测被扫描主机的UDP端口的开放情况。
    UDP探测报文发送函数。该函数原型为:
    void send_udp(struct scaninfo_struct *pscaninfo)
    该函数被UDP_SCAN函数调用,向目标主机的目标端口发送UDP探测报文。
    ICMP响应报文接收函数。该函数原型为:
    void *receivethread(void *args)
    该函数完成Libpcap库相关的初始化工作,包括抓包过滤规则的设置等。在接收到一个数据包时主动调用响应报文处理函数packet_handler()。
    ICMP响应报文处理函数。该函数原型为:
    void packet_handler(u_char *args,const struct pcap_pkthdr *header,const u_char *packet)
    该函数根据收到的报文,来判断被扫描的主机的端口是否打开。
    扫描结果输出函数。该函数原型为:
    void output_scanresult(struct scaninfo_struct scaninfo)
    该函数被主函数调用,用于输出端口扫描结果。

    3.2 数据结构/* 帧头格式 */struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* 目标MAC地址 */ u_char ether_shost[ETHER_ADDR_LEN]; /* 源MAC地址 */ u_short ether_type; /* 上层协议类型 */};/* IP 头格式 */struct sniff_ip { u_char ip_vhl; /* 高4位为IP协议版本,低4位为IP头长度 */ u_char ip_tos; /* 服务类型 */ u_short ip_len; /* 长度 */ u_short ip_id; /* 分片标识 */ u_short ip_off; /* 高3位分片标识,低13位为分片偏移量 */ u_char ip_ttl; /* IP报文生存周期 */ u_char ip_p; /* 上层协议类型标识 */ u_short ip_sum; /* 校验和 */ struct in_addr ip_src,ip_dst; /* IP源地址和IP目标地址 */};/* ICMP 头格式 */struct sniff_icmp{ u_int8_t icmp_type; /* ICMP类型 */ u_int8_t icmp_code; /* ICMP代码 */ u_int16_t icmp_sum; /* 校验和 */ //u_int16_t icmp_id; /* 标识 */ //u_int16_t icmp_seq; /* 序列号 */};/* UDP 头格式 */struct sniff_udp{ u_int16_t udp_sport; /* 源端口号 */ u_int16_t udp_dport; /* 目的端口号 */ u_int16_t udp_len; /* 长度 */ u_int16_t udp_sum; /* 校验和 */};/* 扫描信息结构 */struct scaninfo_struct{ int scan_type; char interface[32]; struct in_addr ipaddr; char ipaddr_string[32]; int startport; int endport; int portnum; pthread_cond_t *cond; int *portstatus; int alreadyscan;};
    3.3 关键算法设计/* UDP探测报文发送函数 */ void send_udp(struct scaninfo_struct *pscaninfo){ int i; for (i = pscaninfo->startport; i <= pscaninfo->endport; i++) { usleep(1000000); //由于Linux系统限制了ICMP目标不可达报文的发送速率,所以应该根据情况控制UDP探测报文的发送速率。 struct sockaddr_in addr; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == -1) { printf("create socket error! \n"); return ; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(i); inet_pton(AF_INET, pscaninfo->ipaddr_string, &addr.sin_addr); int retval = sendto(sock,NULL,0,0,(const struct sockaddr *)(&addr), sizeof(addr));//UDP报文发送 if (retval<0) printf("Send message to Host Failed !"); close(sock); }}//ICMP报文处理函数void packet_handler(u_char *args,const struct pcap_pkthdr *header,const u_char *packet){ struct scaninfo_struct *pscaninfo = (struct scaninfo_struct *)args; const int SIZE_ETHERNET = 14; const struct sniff_ethernet *ethernet; //帧头指针 const struct sniff_ip *ip; //IP头指针 const struct sniff_icmp *icmp; //ICMP指针 const struct sniff_ip *ipw; //产生差错的报文的IP头指针 const struct sniff_udp *udp; //UDP头指针 u_int size_ip; u_int size_icmp; u_int size_ipw; ethernet = (struct sniff_ethernet *)(packet); ip = (struct sniff_ip *)(packet + SIZE_ETHERNET); size_ip = IP_HL(ip) * 4; if (size_ip < 20) return; //判断ICMP报文是否为目的不可达差错控制报文 icmp = (struct sniff_icmp *)(packet+SIZE_ETHERNET+size_ip); if (icmp->icmp_type != 3) return; ipw = (struct sniff_ip *)(packet+SIZE_ETHERNET+size_ip+8); size_ipw = IP_HL(ipw) * 4; if (size_ipw < 20) return; //获取产生差错的报文的目的IP地址 struct in_addr ip_check = ipw->ip_dst; //获取目的不可达差错控制报文的UDP首部 udp = (struct sniff_udp *)(packet+SIZE_ETHERNET+size_ip+8+size_ipw); //获取UDP首部的目的端口号 int dstport = ntohs(udp->udp_dport); if (ip_check.s_addr == (pscaninfo->ipaddr).s_addr) {//判断ICMP不可达报文的差错报文的目的IP地址是否与UDP发送报文一致 if (icmp->icmp_code == 3)//判断ICMP报文是否为端口不可达报文 pscaninfo->portstatus[dstport - pscaninfo->startport] = CLOSE; else pscaninfo->portstatus[dstport - pscaninfo->startport] = UNKNOWN; pscaninfo->alreadyscan++; } if (pscaninfo->alreadyscan >= pscaninfo->portnum) pthread_cond_signal(pscaninfo->cond);}//ICMP报文捕获线程函数void *receivethread(void *args){ struct scaninfo_struct *pscaninfo = (struct scaninfo_struct *)args; bpf_u_int32 net; bpf_u_int32 mask; char errbuf[PCAP_ERRBUF_SIZE]; pcap_lookupnet(pscaninfo->interface, &net, &mask, errbuf); pcap_t *handle; handle = pcap_open_live(pscaninfo->interface, 100, 1, 0, errbuf); if (handle == NULL) { printf("pcap open device failure \n"); return NULL; } struct bpf_program fp; char filter[20] = "icmp"; //过滤函数,只捕获ICMP报文 int retval = 0; retval = pcap_compile(handle, &fp, filter, 0, net); if (retval == -1) return NULL; retval = pcap_setfilter(handle, &fp); if (retval == -1) return NULL; pcap_loop(handle, 0, packet_handler, (u_char *)pscaninfo); return NULL;}
    四、系统实现系统开发的软硬件环境,系统运行截图(对应于系统的功能)以及关键代码(加注释)

    软件环境

    系统:Linux(CentOS 6.5)内核版本:2.6.32-431.11.2.el6.i686gcc编译器版本:gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4)函数库:libpcap-1.5.3
    硬件环境(虚拟机配置)

    CPU: i686网卡
    eth2 encap:Ethernet addr:192.168.174.135 Bcast:192.168.174.255 Mask:255.255.255.0


    运行截图如下:

    五、总结由于大三时期的网络课程没有认真学习,这次网络信息安全实验一下问题就出来了。首先的问题就是socket编程不熟悉,在发送UDP探测报文出现了一些错位,其次就是icmp报文的种类和格式不是很清楚,这直接导致我抓包后分析报文的时候分析不出结果。带着这些问题,认真的查阅相关资料,模仿syn扫描和fin扫描的代码,最终还是写出了实验代码,并成功运行。总的来说,这次的实验暴露了我以前的很多问题,也让我收获很大。这次实验的不足之处在于UDP端口扫描的功能太单一了,不支持网段扫描和多线程扫描。而且被扫描主机一般会限制icmp端口不可达报文的发送速率,这也导致我开发的这个UDP端口扫描速度不够快,我目前也还没找到这个问题有效的解决办法。
    1 评论 1 下载 2019-05-04 10:45:23 下载需要11点积分
  • 基于JAVA的图书管理系统

    1 数据库设计1.1 需求分析1.1.1系统简要分析本系统的用户为图书馆工作人员,系统用户分为管理员和普通用户两种。管理员为系统的高级用户,普通用户为图书馆工作人员。管理员账号和密码预先写入数据库中,账号是每位同学的学号,密码是学号后三位。
    系统为不同用户提供不同的功能:
    1.1.2基本需求功能点分析系统为不同用户提供不同的功能:

    管理员功能:

    登陆:输入管理员帐号和密码,验证通过后可登陆系统。
    用户管理:

    添加系统普通用户为普通用户重置登陆密码。
    图书类别管理:

    添加图书类别,如:政治,经济,军事,医药等。修改图书类别名称。类别查询。
    图书管理:

    添加一本图书。图书信息包括:书名,第一作者,第一出版社,出版年份,状态(正常,报废),类别等。修改图书信息。图书查询。
    读者类别管理:

    添加读者类别,类别信息包括:类别名称,最长借阅天数,最大借阅本数等。修改读者类别名称。读者类别查询。
    读者管理:

    添加读者。读者信息包括:姓名,读者类别,身份证号,联系电话等等。修改读者信息。读者查询。
    普通用户功能:

    系统登陆和密码修改图书馆工作人员凭用户号和密码登陆系统。图书借阅为读者借书。如果该读者的借书量未达到最大借阅本书,且无超期欠费情况,则可以为其登记借书信息;如有欠费,则需先缴费还书。为读者还书。如果该读者所还图书未超期欠费,则可以为其还书;如欠费,则先计算欠费金额,付费后再还书。

    1.1.3 系统运行条件分析此软件系统需要至少一台计算机为服务器Windows操作系统SQL Server 2008 或更高版本数据库服务器
    1.1.4 数据字典


    表名
    字段序号
    字段名
    主键
    类型
    占用字节
    长度
    允许空




    t_borrowing
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10




    3
    borrowingTime

    date
    3
    10



    t_return
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10




    3
    returnTime

    date
    3
    10



    t_reader_bookRelation
    1
    readerId

    int
    4
    10




    2
    bookId

    int
    4
    10



    t_user
    1
    id

    int
    4
    10




    2
    password

    varchar
    50
    50




    3
    username

    varchar
    50
    50




    4
    usertype

    varchar
    20
    20



    t_bookType
    1
    id

    int
    4
    10




    2
    bookTypeName

    varchar
    10
    10




    3
    bookTypeDesc

    varchar
    1000
    1000



    t_book
    1
    id

    int
    4
    10




    2
    bookName

    varchar
    20
    20




    3
    author

    varchar
    20
    20




    4
    bookTypeid

    int
    4
    10




    5
    publisher

    varchar
    20
    20




    6
    publishtime

    varchar
    10
    10




    7
    state

    varchar
    10
    10




    8
    bookDesc

    varchar
    100
    100



    t_readerType
    1
    id

    int
    4
    10




    2
    readerTypeName

    varchar
    20
    20




    3
    theLongestBorrowingDay

    int
    4
    10




    4
    maximumBorrowingNumber

    int
    4
    10



    t_reader
    1
    id

    int
    4
    10




    2
    IDNumber

    varchar
    20
    20




    3
    name

    varchar
    20
    20




    4
    readerTypeid

    int
    4
    10




    5
    tel

    varchar
    11
    11




    1.2 概念结构设计系统E-R图如图

    1.3 逻辑结构设计此部分需要列出由E-R图转化得到的数据表。

    用户表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    用户id


    password
    varchar
    50
    非空
    用户登录密码


    username
    varchar
    50
    非空
    用户名


    usertype
    varchar
    20
    非空,管理员或普通用户
    用户类型




    图书类别表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书类别id


    bookTypeName
    varchar
    10
    非空
    图书类别名


    bookTypeDesc
    varchar
    1000

    图书类别描述




    图书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书id


    bookName
    varchar
    20
    非空
    图书名


    author
    varchar
    20
    非空
    作者


    bookTypeid
    int
    4
    非空,外键
    图书类别id


    publisher
    varchar
    20
    非空
    出版社


    publishtime
    varchar
    10
    非空
    出版时间


    state
    varchar
    10
    正常或报废
    图书状态


    bookDesc
    varchar
    100

    图书描述




    读者类别表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    图书id


    readerTypeName
    varchar
    20
    非空
    读者类型名


    theLongestBorrowingDays
    int
    4
    非空
    最长借阅时间


    maximumBorrowingNumber
    int
    4
    非空
    最大借阅数量




    读者表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    id
    int
    4
    主码
    读者id


    IDNumber
    varchar
    20
    非空
    身份证号


    name
    varchar
    20
    非空
    姓名


    readerTypeid
    int
    4
    非空,外键
    读者类别号


    tel
    varchar
    11

    联系方式




    借书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id


    borrowingTime
    date
    8
    主码
    借阅时间




    还书表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id


    returnTime
    date
    8
    主码
    归还时间




    读者-图书关系表,具体数据如表所示:



    列名
    数据类型
    长度
    约束
    说明




    readerId
    int
    4
    主码
    读者id


    bookId
    int
    4
    主码
    图书id



    1.4 物理结构设计数据库管理系统:SQLServer 2014
    1.5 数据库实施1.5.1 数据库表和视图清单如图所示:

    1.5.2 数据库基本表
    用户表


    图书类别表


    图书表


    读者类别表


    读者表


    借书表


    还书表


    读者-图书关系表

    1.5.3 视图1.5.3.1 view_bookType创建视图代码:
    create view view_bookTypeasselect* from t_bookType
    作用:对图书类别全部属性的查询语句,通过java代码实现可显示在图书类别维护界面的表格中。
    1.5.3.2 view_borrowing创建视图代码:
    create view view_borrowingasselect readerId,IDNumber,name,bookId,borrowingTimefrom t_reader,t_borrowingwhere t_reader.id=t_borrowing.readerId;
    作用:对借书表和读者表部分属性的查询语句,通过java代码实现可显示在图书借阅记录界面的表格中。
    1.5.3.3 view_userlist创建试图代码:
    create view view_userlistasselect * from t_user where usertype='普通用户'
    作用:查询用户类别为普通用户的用户的全部属性,通过java代码显示在重置用户密码界面的表格中。
    1.5.4 存储过程1.5.4.1 existBookByBookTypeId存储过程创建存储过程代码:
    create procedure existBookByBookTypeId(@ID int)as (select*from t_bookwhere bookTypeId=@ID)
    作用:判断指定图书类别下是否有图书
    1.5.4.2 existReaderByReaderTypeId存储过程create procedure existReaderByReaderTypeId(@ID int)as(select*from t_readerwhere readerTypeId=@ID)
    作用:判断指定读者类别下是否有读者
    1.5.5 触发器删除读者触发器
    create trigger triger_deletereaderon t_reader instead of deleteasbeginEXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'--禁用约束delete from t_borrowing where readerId=(select id from deleted)delete from t_return where readerId=(select id from deleted)delete from t_reader where id=(select id from deleted)EXEC sp_msforeachtable 'ALTER TABLE ? CHECK CONSTRAINT ALL' --启用约束end
    作用:删除读者时有外键约束,触发器取消外键约束,删除借书还书记录中该读者的记录,再删除该读者,再启用约束。
    2 系统设计2.1 系统功能模块设计此部分主要描述各个模块具体实现的各项功能点以及模块之间的关系,模块结构划分如图所示:

    2.1.1 管理员用户模块该模块具体功能是管理员对图书系统进行管理,主要包括图书类别管理模块,图书管理模块,读者类别管理模块,读者管理模块,用户管理模块。

    图书类别管理模块:此模块下可进行图书类别的添加和维护,维护包括查询、删除和修改,可以对图书类别名和图书类别描述等属性进行操作。
    图书管理模块:此模块下可进行图书的添加和维护操作,维护包括查询删除和修改,可对图书名称、图书作者、图书类别、出版社、出版时间、图书状态、图书描述等属性进行操作。
    读者类别管理模块:此模块下可进行读者类别的添加和维护,维护包括查询、删除和修改,可对读者类别名称、最长借阅天数和最大借阅本数等属性进行操作。
    读者管理模块:此模块下可进行读者的添加和维护,维护包括查询、修改和删除,可对读者身份证号、姓名、联系方式、读者类别等属性进行操作。
    用户管理模块:此模块下可进行对普通用户的添加和修改普通用户密码操作。

    2.1.2 普通用户具体功能模块该模块具体功能是普通用户登录系统后进行借书和还书操作,主要包括图书借阅和图书归还模块。

    图书借阅模块:此模块下可进行图书借阅操作和对借阅记录的查询操作。图书借阅可添加图书借阅记录。
    图书归还模块:此模块下可进行图书归还操作和对归还记录的查询操作。图书归还可添加图书归还记录。

    2.2 系统功能设计本部分按系统主要功能绘制流程图,说明系统功能将如何现。如图所示:

    3 系统实现3.1系统项目清单系统项目具体所含如图所示:
    model包包含各种实体类,dao包包含各种数据库操作的类,util包包含数据库工具类和字符串工具类,model包包含各种界面类。


    3.2 登录界面登录界面由LogOnFrm.java实现,输入用户名和密码,选择用户类型为管理员或普通用户,验证成功即可进入主界面。用户名或密码错误或未输入则弹出窗体提示。如图所示。

    3.3 管理员主界面管理员主界面由MainFrm.java实现,选中菜单栏中选项选择要显示的功能窗体。如图所示:

    3.3.1 图书类别维护界面

    3.3.2 图书添加图书的添加是管理员向数据库中加入一条图书信息,若图书名称、图书作者等非空数据为空,则弹出提示图书不能为空等。图书类别为一个下拉框,其中显示图书类别表中的图书类别名称。图书状态只有正常和报废两种,用单选按钮实现。图书添加界面如图所示。

    3.3.3 图书维护图书维护界面可实现图书的查询、修改删除。没有操作时中间表格bookTable显示所有图书。进行查询操作时表格中显示查询到的结果。添加了表格行点击事件,点击指定行时,下面的表单操作中的文本框被选中内容填充,修改文本框的内容后点击修改按钮,对数据库执行update操作,修改了数据库中数据,然后界面中bookTable表刷新,显示更新后的数据。点击删除按钮时执行sql的delete操作。图书维护界面如图所示。

    3.3.4 添加普通用户在管理员主界面选择用户管理-添加普通用户弹出菜单如图3-8,输入要添加的用户名和密码,点击添加按钮,提示用户添加成功。如用户名和密码为空则弹出错误提示。重置按钮可清空两个文本框。

    3.3.5 重置用户密码菜单在管理员主界面选择用户管理-重置用户密码菜单如图,可进行查询和修改密码操作。在查询框中输入要查询的用户名,中间的userTable中将显示查询出的信息,运用视图view_userlist。点击要修改的用户所在行,该用户密码将出现在密码修改框的密码文本框中,修改内容,点击修改按钮,弹出用户密码修改成功则完成用户密码修改。选中表中用户点击删除按钮,弹出删除成功提示框,则完成了删除该普通用户操作。

    3.3.6 读者维护界面在管理员主界面选择读者管理-读者维护显示读者维护界面如图。可对读者进行查询、修改、删除操作。查询结果显示在表格中。选择表格中数据可进行修改、删除操作。修改、删除完成后提示修改成功或删除成功。删除操作运用触发器triger_deletereader同时删除被删除读者的借书记录和还书记录。

    3.3.7 读者类别维护界面在管理员主界面选择读者类别管理-读者类别维护显示读者类别维护界面如图。读者类别管理界面可实现对读者类别的查询、修改、删除操作,其中删除操作调用存储过程existReaderByReaderTypeId判断该读者类别下是否有读者。有读者时的错误提示如图。


    3.4 普通用户主界面普通用户主界面由MainFrm2.java实现,选中菜单栏中选项选择要显示的功能窗体。如图所示。

    3.4.1 图书借阅界面在普通用户主界面点击借书-图书借阅显示图书借阅界面如图。输入读者编号和图书编号点击确定,若读者编号和图书编号在t_reader和t_book表中不存在则弹出错误提示框。点击重置两文本框重新为空。借书本数超限提示如图,借书时间超限提示如图。



    3.4.2 图书借阅记录查询在普通用户主界面选择借书-借阅记录查询显示界面如图。在查询框中输入读者身份证号和图书编号,点击查询按钮,可进行查询操作。中间表格运用视图view_borrowing显示查询出来的记录,查询之前显示所有的借书记录。

    4 总结图书管理系统运用java语言,连接数据库,主要用eclipse的windowsbuilder插件完成图形化界面,数据存储在SQL server数据库中,通过SQL语句完成对数据库的操作。
    运用了视图、存储过程、触发器来完善系统。系统完成了对图书、读者、用户等对象的增删改查操作。实现了大部分图书管理系统要求的功能。
    不足:系统虽然完成了图书借阅超过期限的提示,但没有写有关的缴费界面和操作。
    1 评论 21 下载 2019-03-02 17:57:17 下载需要12点积分
  • 基于JAVA实现的网络五子棋游戏

    一、实验目的
    熟练掌握基本网络编程技术
    掌握Swing图形用户界面编程
    掌握多线程编程的基本原理,能使用多线程设计服务器端程序
    培养独立查找资料,并解决问题的能力

    二、实验任务网络五子棋游戏

    服务器端为多线程,当判断有偶数个用户连接时,方可开始游戏
    先连接的客户执黑棋,先下。另一客户执白棋
    双方交替下棋,由服务器端程序判断客户本次下棋步骤是否有效,仅将有效的下棋步骤传递给双方
    客户端程序负责本地下棋界面的显示工作,与服务器通信,并处理相应的鼠标事件
    下棋胜负由客户端自行判定。提供客户退出按钮,点击按钮,将退出游戏
    选作部分

    由服务器端程序判定游戏胜利方,并终止游戏,向双方显示游戏胜利者信息提供玩家注册功能,并保存该玩家胜负局数信息、等级、中途逃逸次数等信息游戏开始时,向双方显示玩家等级、逃逸次数等基本信息,玩家可选择是否继续和对手的游戏

    三、开发工具与平台
    Jdk
    Eclipse

    四、设计思路4.1 界面设计登陆框输入用户名和密码,判断正确方可进入游戏。

    总体布局为BorderLayout,其中西边为用户信息面板,由JLabel加载图片和JTextArea显示信息。中部的棋盘背景为图片,网格线由Graphics2D实现,棋盘的paintComponent( )方法先画图再画线。东边为主机信息和游戏信息,都是JTextArea实现。东边下方的按钮先添加在面板上,在加入东部的面板里。
    4.2 逻辑设计由ServerThread探测是否有客服连接,若有,则为客户创建一个ServerToClientThread,并将其加入Clients的ArrayList集合中,接着验证用户名和密码,验证的信息存在HashMap中,键值为用户名,映射的值为Values的类,类中包含了密码,输,赢,逃跑次数等信息。如果验证成功则将用户信息传给客户端,显示在Info的JTextArea中,客户可以创建游戏或加入游戏,如果创建主机,则别的客户可以加入游戏,由host的ArrayList维护,在登陆成功的同时也会将host和Clients的集合传给客户。
    客户通过JList的选择获得要传送信息的客户,此表与服务器维护的信息相同,所以只需传送选择的Index就可以了。Index通过Clients可以查找到要发送的对象。
    当创建游戏时,ServerThread会将客户对应的ServerToClientThread加入host集合中,并将更新信息传送给Clients中的所有客户。当客户加入游戏时,将对映的信息加入map中,即建立游戏中信息传送对象的信息。
    游戏中的信息通过map查找对手的ServerToClientThread发送。
    4.3 程序测试登陆验证的测试

    下棋及游戏双方的连接测试

    消息的发送测试

    五、实验总结通过这次实验:

    掌握了基本网络编程技术
    掌握Swing图形用户界面编程
    掌握多线程编程的基本原理,能使用多线程设计服务器端程序
    培养独立查找资料,并解决问题的能力

    最大的不足:界面不够美观!
    1 评论 5 下载 2019-05-03 11:28:34 下载需要13点积分
  • 基于Java的远程视频会议系统

    研究背景随着人们对视频和音频信息的需求愈来愈强烈,追求远距离的视音频的同步交互成为新的时尚。近些年来,依托计算机技术、通信技术和网络条件的发展,集音频、视频、图像、文字、数据为一体的多媒体信息,使越来越多的人开始通过互联网享受到网上生活、远程医疗、远程通讯的乐趣,缩短了时区和地域的距离。远程通信的各种优势给人们带来的方便也促使人们对这一领域进行更加深入的探索。基于不同平台以及不同开发工具的网络视频会议系统层出不穷。
    视频会议系统在我国开始发展的初期,政府部门的应用就占据了重要位置,覆盖中央到直辖市和各省会城市的国家公众视频会议骨干网已经完工。自1994年9月投入使用以来,国务院等机关先后利用该网召开了三百多次全国范围的可视通讯会议。整个系统运行情况良好,得到了国家领导人和各部委领导的高度赞扬。近年来随着电子政务工程的逐步推进,政府部门更加关注视频会议系统建设。在经济发达地区(例如浙江、山东、广东),视频会议网已覆盖到地市级城市,有的甚至覆盖到县一级。除各级政府之外,其它诸如检察院、法院、公安和和水利等职能部门也是视频会议系统的重要用户。
    视频会议系统还更广泛的应用于现代企业中。信息技术的迅猛发展,改变了各行各业的传统工作模式。信息的无限量扩大,交通工具的便捷,互联网技术的充分应用等导致了行业间竞争的全球化,这就要求现代部门、企业要具备更加灵敏的神经,更扁平化的管理,更快速的反应和决策,更贴切的市场宣传和服务。所有这一切是由于信息技术的发展带来的,同样也要求有先进的信息技术来提高部门、企业的竞争力。视频会议系统的可以跨越空间距离、灵活多样的面对面的交互,适应现代社会的方便、快捷、高效、快节奏,它为用户带来的经济效益,使视频会议系统的使用正在向各行各业渗透,给这一市场注入了新的活力。
    1 系统概要设计1.1 系统总体设计1.1.1 系统流程​ 服务器端流程如图所示:

    ​ 客户端流程如图 所示:

    1.1.2 系统结构通过学习和研究,我们通过多播技术实现了多点对多点的视频会议系统。整个系统包括这样几个模块:
    文本聊天模块:该功能是网络视频会议的最基本的功能。通过该模块实现了会议成员的聊天通信。首先,每个会议职员通过与服务器连接加入到会议组,同时通过给自己取昵称将自己的昵称发送给服务器,让会议组的每个成员了解自己的身份。会议成员在聊天的时候不是将文本发送给某个人,而是发送给整个会议组。
    视频通信模块:该功能利用JMF软件开发包,基于RTP协议实时发送和接受视频流。并且利用JMF多媒体组件构造播放器,进行实时播放。在实现了点对点的基本视频传输的基础上,我们应用了多播技术。当某个会议成员开始进行视频连接以后,他能通过视频会议系统看到所有其他已经建立视频连接会议成员。
    1.2 系统接口的概要设计1.2.1 服务器端设计系统的服务器端的设计只需显示在线的用户,简单设计图示如下:

    1.2.2 客户端设计系统客户端的设计如下:

    显示在线列表;
    显示界面中用户视频;
    用户聊天文本框;
    视频连接及退出按钮。

    简单设计图示如下:

    2 系统详细设计本系统的详细设计根据概要设计中所划分的各个功能模块进行详细的阐述:
    2.1 文本聊天模块的详细设计本系统要运用Java网络编程中Socket层次,即传统网络编程常采用的方式,通过Client/Server(客户端/服务器端)机构的应用程序之间建立Socket套接字连接,然后在连接之上进行数据通信。
    通过SocketChannel建立基于UDP的无阻塞连接。创建一个无阻塞服务器,让每个客户端与之相连。某个客户端将文本消息发送给无阻塞的服务器,服务器在将这条文本消息组播给各个与之相连的客户端。
    数据在Internet中是以有限大小的包形式传输的,这些包称为数据报(datagram).但是,由于数据报长度有限,通常必须将数据分解为多个包,在目的地再重新组合。有可能一包或多个包在传输中丢失或遭到破坏。由于网络视频会议的实时性要求,不可能让视频传输的每一贞都准确无误。而TCP协议正是为数据可靠传输而设计的。那么选择UDP协议,即用户数据报协议(User Datagram Protocol,UDP),就成为一种必然。
    基于UDP的Socket编程流程图如下:

    服务器:
    serverSocketChannel = ServerSocketChannel.open();//打开连接通道serverSocketChannel.socket().bind(new InetSocketAddress(12345));//绑定IP与端口号getConnection();//接收连接请求客户端:socketChannel = SocketChannel.open();打开连接通道socketChannel.connect(new InetSocketAddress(InetAddress.getByName(serverAddress),12345));//连接到服务器receiveMessage = new ReceivingThread();//构造接收信息线程receiveMessage.start();//运行线程socketChannel.write(writeBuffer);//往通道里写入消息socketChannel.read(readBuffer);//读取通道中消息
    2.2 视频通信模块的详细设计2.2.1 网络视频会议系统结构的详细设计网络视频会议系统其根本目的是会议。会议的基本特征就是,参与会议的每个成员都可以了解到其他成员的状况,每个成员必须到场,然后进行交流,并且每个成员都应该看到所有的交流内容。在这个根本目的完成的基础上,才可以使网络视频会议的特点得以发挥。所以,我们的视频会议系统采用了多播的方法,使得会议的每个成员都可以得到会议的所有信息。
    通过对视频会议基本特点的分析,系统结构图如下图所示:

    2.2.2 视音频传输的详细设计使用JMF API的RTP协议实现网络多媒体程序,可以分为两个部分,一部分是通过网络发送数据的主机端程序,另一部分是接收数据的客户端程序。
    在JMF API中定义了几个与RTP有关的包,即javax.media.rtp、javax.media.rtp.enent、javax.media.rtp.rtcp登包,通过这些包提供的API,可以实现RTP数据流的传输、接受和回放。基于JMF多媒体数据流RTP传输、接受和回放过程图如下:

    数据可以来自于多媒体文件,如视频文件,也可以来自于音/视频采集设备,如声卡、摄像头等。这些数据源的位置不同,格式不同,JMF通过一个称为媒体定位器(Media—Locator)的类对相应的数据源进行定位,MediaLocator对象内仔储了数据源的位置信息。JMF管理器(Manager)根据媒体定位器提供的信息创建数据源。这个数据源和文件、摄像头等物理数据源不同,是一个抽象的概念,是多种不同类型数据源的抽象。这样,JMF可以隐藏底层细节,使编程者在编程过程中不再考虑数据的具体来源和位置,只需考虑数据的格式、速率等信息就行了。
    数据源生成后 ,可以直接交给播放器(Player),设定格式后就可以在本机播放了。但若要将数据流存储成其他格式的文件或者通过 RTP协议在网络上传输 ,则需要对其进行再处理。再处理工作由处理器(Processor)完成 ,处理后的数据源可以存储,也可以在网络上传输。通过 RTP进行传输前 ,需要建立会话管理器(SessionManager),建立 RTP会话后再开始发送流,发送时会打开两个端口,一个用于传输 RTP数据流;另一个用来传输 RTCP包。
    多媒体数据流的接收过程是发送的逆过程。由RTP信道获得的数据流作为接收端的数据源,对数据源处理后便可以实现数据流的回放、存储,甚至再发送。
    详细设计传输过程:
    dsVideo = createDataSource(vf);//创建视频数据源dsAudio = createDataSource(af);//创建音频数据源devices = CaptureDeviceManager.getDeviceList(format);//得到类型为format的设备的清单,存放在表devices中ds = Manager.createDataSource(ml);//通过媒体定位器创建数据源RTPTransmit rtpTransmit = new RTPTransmit(processor,ipAddr,port);//构造RTP会话result = createProcessor();// 产生一个处理器result = createTransmitter();产生RTP会话,将处理器输出的数据传给指定的IP地址的指定的端口号processor.start();// 让处理器开始传输
    2.2.3 多播的详细设计多播基本思想是一个源IP主机只进行一次发送,多个接收者(目标 IP主机)可以接收到相同数据的一个拷贝。但是多个接收者必须都注册加入同一多播组。IP多播服务是一种开放的服务模型,任何主机可以随时加入或退出某个多播组。
    利用这种思想,可以实现会议中的多点对多点的视频传输,已达到组织会议的目的。多播系统结构图:多播实现过程:
    group = InetAddress.getByName(MuiltAddr); //设置组播地址socket = new MulticastSocket(port); //创建MulticastSocket类并将端口与之关联socket.joinGroup(group); //加入此组播组
    2.3 系统界面的详细设计本系统在进行界面设计的时候考虑了系统的功能,对各功能模块进行详细合理的布局:

    把一些功能加到界面中的菜单中,有连接服务器,连接视频,断开连接,退出等子菜单项。
    在界面中添加在线用户列表框,用以显示在线的用户。
    在界面中用一个大的Panel 装载举行会议时的各个用户的视频框。
    在界面中添加实现简单聊天室功能的聊天文本框。
    在界面底端有一些功能按钮,如连接视频,发送信息等。

    3 系统实现3.1 系统实现3.1.1 服务器端套接字建立数据通讯是双向的,客户端通过套接字请求数据通讯后,服务器端需要有一个响应客户端请求通讯的服务程序,该服务器程序应用ServerSocket类完成与客户端的通讯。
    ServerSocket类用来监听和响应客户端的连接请求,并接受客户端发送的数据信息。ServerSocket类在服务器端等待其他机器同它的连接,一旦客户端程序建立一个套接字连接,ServerSocket类就会通过accept()方法返回一个对应的服务器端套接字对象,以便进行直接通讯。从两台计算机连接成功起,服务器端与客户端就得到了一个真正的“套接字-套接字”连接,此时利用Socket类中的getInputStream()及getOutputStream()方法从每端的套接字产生对应的InputStream和OutputStream对象,并将套接字数据流封装到缓冲区内以便进行两台机器之间的数据通讯。
    serverSocketChannel = ServerSocketChannel.open();//打开连接通道serverSocketChannel.socket().bind(new InetSocketAddress(12345));//绑定IP与端口号getConnection();//接收连接请求charSet = Charset.forName("UTF-8");//开启服务器套接字通道serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.socket().bind(newInetSocketAddress(12345)); serverSocketChannel.configureBlocking(false);//设置阻塞模式为非阻塞模式等待一个连接
    3.1.2 客户端套接字建立客户端使用Socket类的方法建立(类似于服务器端),客户端向套接字对象中的数据流输出和获取数据。客户端程序试图与服务器之间在Socket层次上建立一个连接,通过套接字输入流读取方法从套接字数据流中获取服务器信息,以及写入数据到套接字输出流中向服务器发送信息,并且等待服务器的答复。如果连接成功,则该客户端程序通过套接字与服务器可以进行正常的数据交换。
    socketChannel = SocketChannel.open();打开连接通道socketChannel.connect(new InetSocketAddress(InetAddress.getByName(serverAddress),12345));//连接到服务器receiveMessage = new ReceivingThread();//构造接收信息线程receiveMessage.start();//运行线程socketChannel.write(writeBuffer);//往通道里写入消息socketChannel.read(readBuffer);//读取通道中消息
    3.1.3 视音频发送视音频数据以RTP实时流的形式发送出去,通过会话管理器(Session Manager)传输RTP数据的步骤为:

    产生一个JMF处理器(Processor),为每一种RTP格式设置相应的轨迹格式。
    从处理器获取输出数据源。
    会话管理器产生一个发送数据流,即以数据源和序号作为参数调用会话管理器的createSendStream()方
    开始会话传输。
    通过监听ControllerEvent事件控制会话的过程。
    停止会话,删除会话管理器。

    定义以下内容:
    // 媒体定位 IP 端口 处理器 会话管理器 输出数据源private MediaLocator Locator;private String IpAddress;private int portBase;private Processor processor=null;private RTPManger rtpMgrs[];private DataSource dataOutput=null;
    具体实现函数如下:
    //发送数据函数public RTPTransmit(Processor processor,String ipAddress, String pb){}//为媒体定位器产生一个处理器private String createProcessor(){}// 为处理器的每一个媒体磁道产生一个RTP会话private String createTransmitter() {}// 让处理器开始传输public synchronized String start(){}// 停止传输 public void stop(){} //组播线程类class CreateJoinMuiltcastThread extends Thread {}//处理器的状态监听器类class StateListener implements ControllerListener {}
    3.1.4 视音频接收接收网络实时媒体数据流是通过java.media包中定义的各种RTP事件监听器和RTP事件处理类来处理和控制的,使用java.media包中的Player类可以实时播放网络多媒体数据流,java.media包中的处理媒体流接收和播放完成了整个接收RTP数据的过程。接收部分程序为每一种新接收到的媒体数据流产生一个播放器,一边接收媒体流数据,一边将媒体数据播放出来,其实现分为以下几个步骤:

    实现ReceiveStreamListener监听接口,监听NewReceiveStreamEvent事件。
    当接收到NewReceiveStreamEvent事件后,通过事件获取接收媒体数据流(ReceiveStream),然后通过接收媒体数据流获取RTP数据源(DataSource)。
    将数据源传给Manager.createPlayer()产生一个播放器。
    给播放器添加监听器,等到播放器实现后,即可显示播放数据。

    定义以下内容:
    String sessions[] = null; // RTP会话字符串数组RTPManager mgrs[] = null; // RTP管理器数组Vector playerPanels = null; // 管理播放器窗口的向量boolean dataReceived = false; // 是否接收到数据的标志Object dataSync = new Object(); // 同步对象
    具体实现函数如下:
    //接收数据实现函数public Receive(String sessions[]) {}//初始化RTP会话,准备接收数据protected boolean initialize(){}//关闭播放窗口protected void close(){}//判断数据是否接收完成 public boolean isDone() {}// 通过播放器查找播放窗口PlayerPanel find(Player p) {}// 通过接收数据流查找播放窗口PlayerPanel find(ReceiveStream strm) {}//实现ReceiveStreamListener监听接口public synchronized void update( ReceiveStreamEvent evt) {}
    参考文献[1] H.M.Deitel P.J.Deitel,Java 《程序设计教程》 清华大学出版社
    [2] 彭波 孙一林 《Java多媒体技术》 清华大学出版社
    [3] 刘成德 李 祥 《基IPMulticast/JMF的多媒体网络会议系统的设计与实现》
    [4] Elliotte Rusty Harold 《Java网络编程》 中国电力出版社
    [5] 毛黎莉 潘建国 《基于JMF的RTP应用分析与研究》
    [6] 周静 邹北骥 《利用JMF 实现RTP流的传输与播放》
    1 评论 4 下载 2019-02-06 08:38:00 下载需要9点积分
  • 基于Android Studio实现的论坛网站Android客户端和JAVA EE后台

    第一章 概述1.1 开发环境本安卓程序在Windows 10系统下使用Android Studio开发,后台使用MyEclipse开发,测试环境为安卓系统5.1、4.4、4.3、5.0,屏幕尺寸5.0、5.1、5.5的安卓手机。
    1.2 安装配置本安卓程序要求安卓SDK为API level 15以上,target level为23,即,android 4.0.3到android 6.0。
    1.3 需求分析本程序为安卓APP开发项目,项目内容为IT主题的论坛开发。根据需求分析,需要一下功能:

    用户的登陆与注册功能
    用户权限包括管理员、版主、普通用户和游客身份登陆
    根据不同权限登录用户可以对帖子进行不同程度的管理,管理员可以查看、删除所有帖子,版主可以查看所有帖子、删除做属板块的帖子,普通用户和游客都只能查看帖子
    除了游客外所有用户都能发帖、回帖,游客不能发帖、回帖
    用户可以查看自己发的帖子并管理自己的帖子

    第二章 程序概要设计2.1 程序功能模块本安卓程序分为登陆注册模块、查看帖子模块、删除帖子模块、回复帖子模块。

    登陆注册模块是程序的入口,如果已经登陆过了又没有退出登陆,就可以自动登陆,如果没有账号,可以游客登陆
    查看帖子模块可以根据板块选择性查看所有帖子,已注册用户可以查看自己的帖子,帖子信息包括标题、内容、时间等
    删除帖子模块包括管理员可以删除所有帖子,版主可以删除所属板块的帖子,所有用户可以删除自己的帖子,游客不能使用删除功能,程序根据登陆用户的权限自动显示是否可以使用
    回复帖子模块用于已注册用户对帖子的回复,游客不能回复帖子

    2.2 流程图
    2.3 程序文件结构分析java文件夹下MyWork包内的java文件是每个布局对应的Activity,其中Circle是自定义的一个控件;control包下是两个适配器,包括主页面的适配器MainAdapter和回复页面的适配器LookAdapter,还有联网的工具类NetWord。

    res资源文件夹下的layout布局资源文件包括各个Activity的布局和listview的自布局,其中tool_bar是ToolBar的布局。

    menu文件夹下是两个ToolBar的菜单布局,values文件夹下使用到了strings文件和colors文件,特别的是attrs文件,这个是Circle自定义控件的配置文件。

    2.4 数据库设计本程序使用javaEE后台,数据库为sql server,包括card表、section表和userTable表,分别的字段如下:

    card:id、nameId、contents、date、title、sectionId、replyId、isTop、topDate
    section:id、name、host
    userTable:id、username、password、power、pic

    第三章 程序详细设计3.1 关键代码分析联网:使用java jdk自带的HttpURLConnection进行联网,并使用json进行数据传输。图3-1包括了链接网络的方法connect()、传参的输出流ObjectOutputStream,图3-2判断了状态码是否为200然后接收后台传过来的参数并处理返回,接收参数使用InputStream输入流。


    自定义适配器:先写了继承BaseAdapter的适配器类,这个项目中使用了两个适配器,分别为MainAdapter、LookAdapter,作为主界面和回复节目的适配器。两个泪重写了getView方法,处理每个listview中每个item的布局,以显示每一个帖子。
    侧滑菜单:在布局中使用DrawerLayout如图3-3,在Activity中使用ActionBarDrawerToggle作为侧滑开关,并实现开和关的监听,如图3-4。


    界面返回刷新:使用Intent跳转时用startActivityForResult,并重写onActivityResult方法,如图3-5。

    3.2 疑难问题解决用户权限识别:在第一次登陆成功后将后台返回的用户信息存进SharedPreferences,后面根据从中取出来的权限信息进行判断,然后决定是否显示相应按钮。

    第四章 程序的发布和测试4.1 发布过程安卓端的发布,将程序运行到手机,通过android studio的Logcat查看运行信息;
    JavaEE端的发布,将程序部署到Tomcat,同样通过myeclipse的Logcat查看运行信息。
    4.2 测试过程图4-1为登陆界面,点击注册按钮到如图4-2的注册界面,注册成功后跳转回登陆界面登陆。



    登录
    注册









    图4-3为管理员登陆的界面(还有打开侧滑菜单的状态),图4-4为版主和普通用户及游客登陆后的界面。



    管理员登录
    普通用户登录









    图4-5为游客登陆的侧滑菜单界面,与其他用户是不同的,只有一个选项,当其他用户登录时,可以点击右上角的笔进入发帖节目,如图4-6。



    侧滑菜单界面
    发帖









    第五章 分析与总结5.1 优点本安卓程序的优点在于界面简洁,有与服务器后台联系,交互友好,基础功能及部分拓展功能已经实现。
    5.2 缺点本安卓程序的缺点在于界面跳转仍有部分不流畅,因为代码效率问题有待改进,还有其他计划中的拓展功能由于时间关系还没实现。
    5.3 总结通过此次安卓大作业的开发,让我对安卓开发更加熟悉,对知识点的运用更加熟练,由于运用到了javaEE后台,使我对javaEE的熟练度也增加了。因为这次大作业的制作时间比较短,所以刺激了自己的潜力,锻炼了自己赶项目的感觉。
    第六章 参考目录[1] 《疯狂安卓讲义》 电子工业出版社 李刚 2015.8
    [2] 《android应用开发学习手册》 清华大学出版社 管蕾 2015.7
    2 评论 55 下载 2018-11-06 15:32:08 下载需要10点积分
  • 基于C#实现的电影院售票管理系统

    一、引言1.1选题背景随着互联网和电子商务的快速发展,网上购物已经成了现代人生活中很重要的一种方式,如:数码产品、生活用品、化妆品护肤品等,只要是人们需要到的东西,基本都可以在网上购买。除了购买各种物品,现代人的生活也不再向过去一样单调,除了学习和工作之余,人们的娱乐生活也逐渐丰富,最普遍的娱乐休闲方式之一就是到电影院看电影,那么传统的电影订票窗口显然已经不能满足人们的需要了,所以开发一个电影院网上订票系统是非常必要和可行的。以前传统的电影票订票方法是去电影院的购票窗口查看电影的上映时间、场次、可选座位等信息再进行购票,人们往往需要排队才能买到电影票,这样不仅浪费了人们宝贵的时间,而且电影院工作人员的工作量也很大,对于这种低效率、浪费时间的事情,完全可以以网上购票的方式来改变。
    为了提高劳动的效率、节约成本、提高服务质量,我们小组开发了此款系统,用以方便影院的售票和客户的购买,通过这个系统,可以很快的实现会员注册、登录、购票,后台管理员可以新增影片、排片等基本操作。
    二、需求分析2.1 用户需求需要在网上购买电影票的用户可使用本系统,进行会员的注册登陆之后可以进行网上查询电影、购买电影票等操作,省去了去电影院实体窗口排队买票的繁 琐程序。
    2.2 系统功能分析
    新用户的注册、登录,用户数据能存在后台数据库中
    电影的录入、删除、查询、修改
    电影的排片
    管理员查询会员级别等信息
    会员查询影片信息
    会员购买电影票

    2.3 条件与限制系统可以实现一些基本的购票功能,但系统较简单,尚存在很多缺陷,不能实现完善和全面的功能。
    缺陷:

    首先要使用admin进行登录才能开始注册会员
    购票后无法查看购票信息
    不可以支持选座
    购票时不能通过搜索影片名字等来查找影片

    三、模块设计3.1 系统流程图系统流程图如图一所示:

    系统功能图如图二所示:

    3.2 系统使用指南对于用户
    首先,系统使用者先通过admin登录,进入到新用户注册页面,以管理员的身份为用户注册一个新的会员账号,已注册好的账号密码自动保存在后台数据库中,用户下次可以直接使用已注册的会员账号登录本系统进行电影的查询、购票等操作。
    对于管理员
    首先,管理员可以为新用户注册不同级别的会员账号、查看会员的信息。其次,管理员可在系统后台做电影的录入、删除、查询、修改等基本操作,除此之外,添加好影片后可以对电影进行的排片。
    四、数据库设计及实现4.1 系统E-R图E-R图如图三所示:

    4.2 逻辑结构设计(关系数据库设计)
    顾客(Cus、CusCard、CusType、CusTel(key))
    登陆(UserName、UsePwd、UserType)
    电影(Mname(key)、MBZ、MLanguage、MTYPE、MDirector、MACT、MTime)
    排片(MName(key)、MPrice、MRoom、Mcount、MTime、MBRQ、MERQ)
    上映(ID(key)、MName、MPrice、MRoom、MCount、MTime、MRQ)
    购票(PID(key)、Cname、GPCount、GPJE、MName、SYRQ、FYT、GPRQ、CZY)

    4.3 数据库主要代码及触发器会员信息
    CREATE TABLE [dbo].[Cus]( [CusTel] VARCHAR(50) NOT NULL PRIMARY KEY, [CusName] VARCHAR(50) NOT NULL, [CusCard] VARCHAR(50) NULL, [CusType] VARCHAR(50) NULL)
    触发器
    SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER TRIGGER [dbo].[InsertULogin] on [dbo].[Cus]after insertasdeclare @username varchar(50)declare @userpwd varchar(50)select @username=CusTel from inserted select @userpwd= right(CusCard,6) from inserted insert into ULogin values(@username,@userpwd,'C')
    购票信息
    CREATE TABLE [dbo].[GP]( [PID] VARCHAR(50) NOT NULL PRIMARY KEY, [CName] VARCHAR(50) NOT NULL, [GPCount] INT NULL, [GPJE] FLOAT NULL, [MName] VARCHAR(50) NULL, [SYRQ] VARCHAR(50) NULL, [GPRQ] VARCHAR(50) NULL, [CZY] VARCHAR(50) NULL, [FYT] VARCHAR(50) NULL)
    触发器
    SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER TRIGGER [dbo].[UpdatePP] on [dbo].[GP]after insertasdeclare @MName varchar(50)declare @SYRQ varchar(50)declare @count intselect @MName= MName,@SYRQ=SYRQ,@count=GPCount from inserted update MovieSY set mcount=mcount-@count where MName=@MName and MRQ=@SYRQ
    电影信息
    CREATE TABLE [dbo].[Movie]( [MName] VARCHAR(50) NOT NULL PRIMARY KEY, [MLanguage] VARCHAR(50) NOT NULL, [MDirector] VARCHAR(50) NULL, [MAct] VARCHAR(50) NULL, [MName] INT NULL, [MBZ] VARCHAR(255) NULL, [MType] VARCHAR(50) NULL)
    上映信息
    CREATE TABLE [dbo].[MovieSY]( [ID] INT NOT NULL PRIMARY KEY, [MName] VARCHAR(50) NOT NULL, [MRoom] INT NULL, [MCount] varchar(50) NULL, [MName] INT NULL, [MTime] VARCHAR(50) NULL, [MRQ] VARCHAR(50) NULL)
    排片信息
    CREATE TABLE [dbo].[PP]( [MName] VARCHAR(50) NOT NULL PRIMARY KEY, [MPrice] INT NOT NULL, [MRoom] VARCHAR(50) NULL, [MCount] INT NULL, [MTime] VARCHAR(50) NULL, [MBRQ] VARCHAR(50) NULL, [MERQ] VARCHAR(50) NULL)
    触发器
    SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER TRIGGER [dbo].[InsertPP] on [dbo].[PP]after insertasdeclare @MName varchar(50)declare @BRQ varchar(50)declare @ERQ varchar(50)declare @MTime varchar(50)declare @MRoom varchar(50)declare @MPrice intdeclare @MCount intdeclare @MBRQ datetimedeclare @MERQ datetimedeclare @RQ varchar(50)select @MName= MName,@BRQ=MBRQ,@ERQ=MERQ,@MTime=MTime,@MRoom=MRoom,@MPrice=MPrice, @MCount=MCount from inserted set @MBRQ=CONVERT (datetime,@BRQ)set @MERQ=CONVERT (datetime,@ERQ)while @MBRQ<=@MERQbegin set @rq=CONVERT(varchar(50), @MBRQ, 112)insert into MovieSY values(@MName,@MPrice,@MRoom,@MCount,@MTime,@RQ) set @MBRQ=DATEADD(DAY,1,@MBRQ)endCREATE TABLE [dbo].[MovieSY]( [UserName] VARCHAR(50) NOT NULL PRIMARY KEY, [UserPwd] VARCHAR(50) NOT NULL, [UserType] VARCHAR(50) NULL)
    五、系统设计与实现5.1系统开发环境
    硬件环境

    Intel Pentium 166MHz或以上;内存:需要至少512MHZ;
    软件环境

    运行于Windows2010版的操作系统之上;SQL Server2008数据库;Visual Studio2013;

    5.2 功能模块
    输入功能模块
    查询显示功能模块
    查询、售票功能模块
    登录、注册功能模块

    5.3 系统主要页面展示登录、注册页面

    登陆后的页面

    会员注册页面

    会员信息查询页面

    添加影片页面

    查询修改影片页面

    排片页面

    “排片”页面通过连接数据库,可以搜索影片的名字、导演、主演来选择影片,再输入票价,放映大厅,座位数,放映时间等信息,最后确认排片。
    购票页面

    购票页面通过对获得的已经被排片的电影进行选择而进行购票这一操作。在购票前需填入购票数量、联系电话,系统会自动计算合计金额。之后点击购票按钮则能进行购票操作。但一旦购票成功则不能进行退票操作,也不能查看所购买的电影票。
    数据库页面

    六、主要特色6.1 系统实用性系统首先可以进行新用户的注册,用户数据能存在后台数据库中。管理员可以进行电影的录入、删除、查询、修改,添加好影片后进行电影的排片。退出登录后再使用之前注册的会员登录,可以购买电影票。
    6.2 突出优势和特色(创新点)
    购票时可以看到影片的导演、主演等信息
    用户分为钻石用户,白金用户和普通用户,对用户进行了分类

    7 小结数据库技术课程设计是一次对课堂所学知识的灵活应用,是理论知识与实践的相结合。经过了一周的课程设计,本系统基本达到了当初的设计要求,设计上也基本合理。我们不仅对数据库系统的认识更加深入,同时也掌握了面向实体的系统分析的基本方法,对VS也有了新的认识,也知道了要有坚持不懈,不惧困难的精神,才能取得成功。一个简单的系统,每一个细节都需要在实践中去挖掘并进行进一步的修改完善。本次课设让我们受益匪浅,在分析问题以及解决问题等方面的能力有所提高,也是一次很好的同学之间交流合作的机会。数据库技术的用途很广,还有很多值得我们学习,希望今后能有更多这样的机会。
    5 评论 34 下载 2019-01-01 18:20:12 下载需要18点积分
  • 基于java的多人聊天程序课程设计

    一、设计内容及要求1.1 设计内容聊天工具大多数由客户端程序和服务器程序外加服务器端用于存放客户数据的数据库组成,本程序采用客户机/服务器架构模式。通过Java提供的Socket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能。用多线程可完成多点对多点的聊天。
    1.2 设计要求主要有两个应用程序,分别为服务器程序和客户端程序。服务器应用程序主要用于消息转发、客户登录信息的管理以及向所有用户发送系统消息等;客户端应用程序主要用于客户聊天记录的显示和信息输入。采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。聊天服务器专门用于监控用户状态和转发消息,客户端负责接收消息的用户序列和消息文本发送到服务器。该聊天系统实现私聊,群聊,用户注册,登陆,退出聊天系统等功能。
    二、系统需求分析2.1 系统介绍在当今信息时代,有许多的聊天工具,例如QQ、微信等。本程序就是利用Java网络编程的知识,采用客户机/服务器架构模式来实现客户端与客户端之间的通讯。
    2.2 开发背景在当今信息时代,越来越多的聊天工具被应用,Java语言是当今流行的网络编程语言,它具有面对对象、跨平台、安全、多线程等特点。使用Java语言不仅可以实现大型企业级的分布式系统应用,还能为小型的、嵌入式设备进行应用程序开发。面对对象的开发方法是当今最流行的开发方法,它不仅更贴近现实,而且有利于软件的维护和继承。为了进一步巩固课堂上所学到的知识,深刻把握Java语言的重要概念及面对对象的特性,锻炼我们熟练的应用面对对象的思想和设计方法解决实际问题的能力,所以我选择了开发Java多人聊天程序。
    三、系统总体设计3.1 系统功能结构图
    3.2 系统数据流程图
    四、系统详细设计4.1 本设计所涉及技术和知识点
    C/S体系结构:采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。其中客户端用了发送和接受收显示聊天消息,服务器用来监听客户端的消息,并将接收到的数据转发到所用的客户端上,这样实现群聊功能。Socket套接字:作为多人聊天程序,网络编程的知识必不可少,其中用到了Socket套接字、IP地址、端口号等网络编程的知识。客户端与服务器的窗口用到Java Swing图形用户界面知识,其中包括界面的布局、组件的使用以及各种监听事件的使用。多线程:为了是客户端与客户端之间的消息、客户端发送与接收的消息不发生冲突,将每个客户端的发送和接收用不同的线程。IO流:聊天时客户端与服务器之间肯定有数据的输入输出,所以IO流的知识在这里也十分重要。
    4.2 功能模块详细设计
    客户端:运行客户端时,弹出登录客户端界面,这是需要设置用户名、IP地址和端口号,其中IP和端口号必须和服务器的对应,否则连接不上服务器。登录后进入客户端聊天界面窗口。这时可以与其他客户端之间在一个聊天室中聊天,若想私聊某人,只需在聊天内容前加上@该用户的姓名+:就可以了。点击右上角的下线按钮即退出该聊天室。
    发送消息:当点击发送按钮时,将消息通过DataOutputStream流中的writeUTF发送到服务端,服务端通过DataInputStream中的readUTF接受客户端的消息,紧接着服务端通过DataOutputStream中的writeUTF发送个所有客户端。
    私聊:当用户登录后,在没有点击发送按钮前,先将该客户端的姓名发送到服务器,服务器先接收到用户的姓名,然后在接收聊天消息。
    服务器:启动服务器,弹出设置服务器的窗口,填写服务器的IP地址和端口号,点击确定后,服务器启动,并不断监听客户端的连接和接收客户端发来的消息。

    五、编码与实现5.1 具体功能模块实现该多人聊天程序包括8个文件,功能如下:
    1. Client.java 包含Client类,其中有main、connectServer函数,是客户端启动的入口。在main函数中通过创建一个ClientLogin对象,来打开登陆窗口。 ClientLogin login = newClientLogin();
    2. ClientFrame.java
    包含ClientFrame类,该类继承于Jframe类,用来创建客户端的窗口。 其中包括窗口中的各个组件、布局以及组件的监听事件。
    sendButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { msg = msgText.getText().toString(); ClientSend.send(); msgText.setText(null); });
    发送按钮的监听事件,当点击发送时,将发送栏中的消息保存在字符串msg中,在,然后调用 ClientSend.send()函数,将该字符串发送到服务器。
    3. ClientLogin.java
    包含ClientLogin类,该类继承于Jframe类,用来创建客户端登录窗口,其中包括设置IP地址、端口号、用户姓名的各种组件,和登录按钮的监听事件:
    btn_login.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { name = jtf_userName.getText().toString(); ip = jtf_ip.getText().trim(); port = Integer.parseInt(jtf_port.getText().toString()); //点击登录后,客户端连接服务器 try { Client.connectServer(); } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } //隐藏当前窗口 dispose(); //关闭 //打开客户端 new ClientFrame(); } });
    点击登录按钮时,将窗口中用户姓名、IP地址和端口号分别赋值给字符串name、ip、port变量,然后调用Client.connctServer()来连接服务器,并且关闭该窗口,创建ClientFrame对象来打开客户端窗口。
    4. ClientReceive.java
    包含ClientReceive类,该类中有Runnable接口,用于创建一个用户接受服务器消息的客户端接受线程。
    线程体:
    public void run() { String msg = null; while(isRunning){ //将接受信息输出到客户端窗口中 msg = receive(); System.out.println(msg); ClientFrame.msgRecordText.append(msg+"\n"); } }
    该线程处于死循环中,其中receive()函数用来接收服务器的消息,并通过ClientFrame.msgReceordText.append(msg+”\n”)将消息显示在客户端的窗口聊天记录面板上。
    5. ClientSend.java
    包含ClientReceive类,该类中有Runnable接口,用于发送消息,该线程的线程体为空:
    public void run() { }
    当用户点击客户端窗口中的发送按钮时,会调用该类中的send函数,用于将消息发送到服务器。
    6. Server.java
    包含Server类,其中包含main、setServer方法和List<ServerForward>集合类。
    其中main函数是服务器的入口,用来打开服务器设置窗口。
    main函数:
    ServerFrame serverFrame = new ServerFrame();
    setServer函数:
    public static void setServer() throws IOException { //从服务器窗口获取ip和端口号 String ip = ServerFrame.ip; int port = ServerFrame.port; ServerSocket server = new ServerSocket(port, 0,InetAddress.getByName(ip)); while(true) { Socket client = server.accept(); System.out.println("连接成功"); ServerForward serverForward = new ServerForward(client); allClient.add(serverForward); Thread thread = new Thread(serverForward); thread.start(); } }
    启动服务器,不断的监听客户端的连接,当有客户端连接上时,在List<ServerForward>集合类中添加该线程,并启动该线程。
    7. ServerForward.java
    包含ServerForward类,服务器接受一个客户端得信息,再转发给其他客户端。该类中主要包括receive、send函数,用于转发客户端的消息。
    线程体:
    public void run() { //接受用户的昵称 while(isRunning) { if (name == null) name = getClientName(); else break; } while(isRunning) { sendToClient(receive()); } }
    因为服务器的工作不间断的,所以用无限循环。getClientName()从客户端中接受用户的姓名,并保存字符串name中。sendToClient(receive())接收一个客户端的消息,并转发给所有客户端。
    8. ServerFrame.java
    包含serverFrame类,该类继承于JFrame,用于创建服务器设置界面,其中包括设置IP地址、端口号,和确认按钮的监听事件:
    btn_set.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ip = jtf_ip.getText().trim(); port = Integer.parseInt(jtf_port.getText().toString()); //关闭窗口 dispose(); //点击确定后,设置服务器ip和端口号 try { Server.setServer(); } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } });
    将服务器设置窗口中的IP地址和端口信息ip、port字符串中,并调用Server.setServer函数,开始启动服务器。
    5.2 演示界面5.2.1 服务器设置窗口
    5.2.2 客户端登录窗口
    5.2.3 客户端窗口
    5.2.4 群聊和私聊
    2 评论 60 下载 2018-10-21 14:43:22 下载需要4点积分
  • 基于Java和Sql Server 2012实现的高校成绩管理系统

    1、需求分析计算机已经深入到日常工作和生活的方方面面,成为我们学习和工作的得力助手,比如文字处理、信息管理、辅助设计、图形图像处理、教育培训以及游戏娱乐等。随着越来越多的应用软件出现,人们对它的要求也越来越高;虽然现在世界上的各种软件层出不穷,但它们依然不能满足用户的各种特殊需要,所以人们仍是不得不开发适合特殊需求的软件。高校成绩管理系统记录了一个大学生成绩的系统,它的出现使得查询、更新、插入简单化,高效化,成本也随之大大减少。使用计算机对成绩信息的管理,具有手工管理所 无法比拟的优点:信息存储及时,检索迅速、查找方便、可靠性高、存储量大、保密性好、寿命长、成本低等。这些优点能够极大地提高学 生成绩管理的效率,也是高校成绩正规化管理的重要途径。
    本软件控件均以中文形式表示,对普通程序使用者的查询提供简单方便的快捷操作,不需要技术含量。
    以SQL SERVER数据库管理系统为平台,通过设计数据库概念模型、逻辑模型以及利用标准SQL语言的数据库实现,掌握关系数据库系统的设计与实现方法,增强数据库设计和数据库应用系统开发能力。
    操作人员与维护人员应懂的SQL语言。

    硬件环境

    LENOVO-G470
    软件环境

    Windows 8企业版Microsoft SQL Server 2012 UltimateNETBEANS 7.3

    1.1 数据需求描述
    1.2 系统功能需求
    管理员

    添加教师名单查询教师名单修改教师信息删除教师名单添加学生名单查询学生名单修改学生信息删除学生名单统计生源地信息修改密码
    教师

    查看个人信息查看每门课程平均成绩统计输入学生成绩, 自动生成该学生已修总学分查看任课信息查看学生成绩名次修改密码
    学生

    查看个人信息查看自己的课表查看不同班级的开课情况查询考试成绩修改密码

    1.3 其他性能需求
    用户输入出错时,有错误提示
    给管理员,教师,学生不同的权限,提高数据安全性
    创建触发器,存储过程,防止数据不一致


    2、概念结构设计
    3、逻辑结构设计
    教师(教师编号、教师姓名、教师性别、教师年龄、职称、联系电话)
    上课(教师编号,班级编号)
    授课(教师编号,课程编号)
    课程(课程编号,课程名称,教师姓名,学期,学时,考试或考查,学分)
    学习(学号,课程编号,学期,课程名称,成绩)
    学生(学号、学生姓名、学生性别、学生年龄、生源所在地、已修学分总数,班级编号)
    开设(课程编号,班级编号)
    班级(班级编号,班级名称,专业编号)
    专业(专业编号,专业名称)
    学生账号(学生编号,学生密码)
    教师账号(教师编号,教师密码)
    管理员账号(管理员编号,管理员密码)

    3.2 数据类型定义教师



    数据项名
    数据类型
    长度
    完整性约束




    教师编号
    char
    20
    主键,唯一,非空


    教师姓名
    char
    20



    教师性别
    char
    2



    教师年龄
    char
    20



    职称
    char
    10



    联系电话
    char
    20



    上课



    数据项名
    数据类型
    长度
    完整性约束




    教师编号
    char
    20
    主键,唯一,非空,外键


    班级编号
    char
    20
    外键



    授课



    数据项名
    数据类型
    长度
    完整性约束




    教师编号
    char
    20
    主键,唯一,非空


    课程编号
    char
    20
    外键



    课程



    数据项名
    数据类型
    长度
    完整性约束




    课程编号
    char
    20
    主键,唯一,非空


    课程名
    char
    20



    教师姓名
    char
    20



    开课时间
    char
    20



    学时
    int
    10
    >0


    考试或考查
    char
    4



    学分
    int
    4
    >0



    学习



    数据项名
    数据类型
    长度
    完整性约束




    学生学号
    char
    20
    主键,唯一,非空


    课程编号
    char
    20
    外键


    学期
    char
    10



    课程名称
    char
    20



    成绩
    int
    10



    教师姓名
    char
    20



    学生



    数据项名
    数据类型
    长度
    完整性约束




    学生学号
    char
    12
    主键,唯一,非空


    学生姓名
    char
    10



    学生性别
    char
    2



    学生年龄
    int
    4



    生源所在地
    char
    20



    已修学分总数
    int
    4



    班级编号
    char
    10
    外键



    开设



    数据项名
    数据类型
    长度
    完整性约束




    课程编号
    char
    20
    联合主键,唯一,非空


    班级编号
    char
    20



    班级



    数据项名
    数据类型
    长度
    完整性约束




    班级编号
    char
    20
    主键,唯一,非空


    班级名称
    char
    20



    专业编号
    char
    20
    外键



    专业



    数据项名
    数据类型
    长度
    完整性约束




    专业编号
    char
    20
    主键,唯一,非空


    专业名称
    char
    20



    学生账号



    数据项名
    数据类型
    长度
    完整性约束




    学生编号
    char
    20
    主键,唯一,非空


    学生密码
    char
    20



    教师账号



    数据项名
    数据类型
    长度
    完整性约束




    教师编号
    char
    20
    主键,唯一,非空


    教师密码
    char
    20



    管理员账号



    数据项名
    数据类型
    长度
    完整性约束




    管理员编号
    char
    20
    主键,唯一,非空


    管理员密码
    char
    20



    3.3 关系模式的优化对关系模式进行规范化处理,对关系模式进行评价与修正。
    4、物理结构设计4.1 聚簇设计该高校成绩管理系统数据库可建立聚簇:














    这几个聚簇设计是因为这几张表都是实体表,,且聚簇中的属性都是主键或是外键,被访问的概率很高,而其他表或者这些表上的其他属性被访问的概率就相对较低。
    4.2 索引设计索引就是表中数据和相应存储位置的列表,使用索引可以大大减少数据的查询时间。
    对于一个确定的关系,通常在下列情况下可以考虑建立索引。

    在主键属性列和外键属性列上通常都可以分别建立索引,不仅有助于唯一性检查和完整性检查,而且可以加快连接查询的速度
    以查询为主的关系可建立尽可能多的索引
    对等值连接,但满足条件的元组较少的查询可以考虑建立索引
    如果查询可以从索引直接得到结果而不必访问关系,则对此种查询可以建立索引

    该高校成绩管理系统数据库可建立以下索引:

    教师(教师编号)
    课程(课程编号)
    学生(学生学号,班级编号)
    班级(班级编号)
    学习(学号,课程编号)

    4.3 分区设计涉及到数据库文件和日志文件的分区问题。
    磁盘分区设计的一般原则:

    减少访问冲突,提高I/O并发性。多个事物并发访问同一磁盘时,会产生磁盘访问冲突而导致效率低下,如果事务访问数据均能分布于不同磁盘上,则I/O可并发执行,从而提高数据库访问速度
    分散热点数据,均衡I/O负担。在数据库中数据访问的频率是不均匀的,那些经常被访问的数据成为热点数据,此类数据宜分散存在于不同的磁盘上,以均衡各个磁盘的负荷,充分发挥多磁盘的并行操作的优势
    保证关键数据快速访问,缓解系统瓶颈。在数据库中有些数据如数据字典等的访问频率很高,为保证对它的访问不直接影响整个系统的效率,可以将其存放在某一固定磁盘上,以保证其快速访问

    该成绩管理系统由于程序较小,所以不进行分区设计。
    5、数据库实施建立数据库D01jiangnan

    5.1 基本表建立教师
    CREATE TABLE 教师jn( 教师编号jn CHAR(20) PRIMARY KEY, 教师姓名jn CHAR(10), 教师性别jn CHAR(2), 教师年龄hn INT, 职称jn CHAR(20), 联系电话jn CHAR(10),);
    专业
    CREATE TABLE 专业jn( 专业编号jn CHAR(20) PRIMARY KEY, 专业名称jn CHAR(20),);
    班级
    CREATE TABLE 班级jn( 班级编号jn CHAR(20) PRIMARY KEY, 班级名称jn CHAR(20), 专业编号jn CHAR(20) constraint Major_Class foreign key(专业编号jn) references 专业jn);
    课程
    CREATE TABLE 课程jn( 课程编号jn CHAR(20) PRIMARY KEY, 课程名jn CHAR(20), 教师姓名jn CHAR(10), 学时jn INT, 考试或考查jn CHAR(4), 学分jn CHAR(4));
    学生
    CREATE TABLE 学生jn( 学生学号jn CHAR(20) PRIMARY KEY, 学生姓名jn CHAR(10), 学生性别jn CHAR(2), 学生年龄jn int, 生源所在地jn char(20), 已修学分总数jn int, 班级编号jn CHAR(20) constraint Class_Student foreign key(班级编号jn) references 班级jn);
    上课
    CREATE TABLE 上课jn( 教师编号jn CHAR(20) , 班级编号jn CHAR(20) , PRIMARY KEY(教师编号jn,班级编号jn), CONSTRAINT Class_Teach1 FOREIGN KEY(教师编号jn) REFERENCES 教师jn, CONSTRAINT Class_Teach2 FOREIGN KEY(班级编号jn) REFERENCES 班级jn,);
    授课
    CREATE TABLE 授课jn( 教师编号jn CHAR(20) PRIMARY KEY, 课程编号jn CHAR(20), CONSTRAINT Course_Instruct FOREIGN KEY(课程编号jn) REFERENCES 课程jn CONSTRAINT Course_Instruct2 FOREIGN KEY(教师编号jn) REFERENCES 教师jn);
    学习
    CREATE TABLE 学习jn( 学生学号jn CHAR(20) , 课程编号jn CHAR(20), 学期jn char(10), 课程名称jn char(20), 成绩jn int, 教师姓名jn char(20), primary key(学生学号jn,课程编号jn), CONSTRAINT Course_Study FOREIGN KEY(课程编号jn) REFERENCES 课程jn);
    开设
    CREATE TABLE 开设jn( 课程编号jn CHAR(20) , 班级编号jn char(20), primary key(课程编号jn,班级编号jn), CONSTRAINT Class_Setup FOREIGN KEY(班级编号jn) REFERENCES 班级jn);
    5.2 视图的建立学生成绩统计
    create view 学生成绩统计jnas select 学习jn.学生学号jn,学生姓名jn,学习jn.课程名称jn, 班级名称jn,学习jn.教师姓名jn,学分jn,课程jn.学期jn,成绩jn from 学生jn, 课程jn, 班级jn,学习jn where 学生jn.学生学号jn = 学习jn.学生学号jn AND 学习jn.课程编号jn = 课程jn.课程编号jn AND 班级jn.班级编号jn = 学生jn.班级编号jn
    每门课程平均成绩统计
    create view 每门课程平均成绩jnas select avg(成绩jn) 平均成绩jn,课程编号jn from 学习jngroup by 课程编号jn
    学生所学课程及学分统计
    create view 学生所学课程及学分统计jn as select 学生学号jn, 课程名称jn, 学分jn from 学生成绩统计jn
    教师任课查询
    create view 教师任课查询jnas select 教师jn.教师编号jn, 课程jn.教师姓名jn, 课程jn.课程编号jn, 课程名jn, 学时jn, 学分jn from 教师jn, 课程jn,授课jn where 授课jn.课程编号jn=课程jn.课程编号jn and 授课jn.教师编号jn=教师jn.教师编号jn
    班级课程开设查询
    create view 班级课程开设查询jnas select 班级jn.班级编号jn, 班级jn.班级名称jn, 课程jn.课程编号jn, 课程名jn, 学时jn,学分jn from 班级jn, 课程jn,开设jn where 班级jn.班级编号jn = 开设jn.班级编号jn AND 开设jn.课程编号jn = 课程jn.课程编号jn
    地区学生数统计
    create view 地区学生数统计jnas select 生源所在地jn,count(学生学号jn) 地区学生总数jn from 学生jn group by 生源所在地jn
    5.3 索引的建立教师编号
    create unique index UI_教师编号jnon 教师jn(教师编号jn)
    专业编号
    create unique index UI_专业编号jn on 专业jn(专业编号jn)
    班级编号,专业编号
    create unique index UI_班级及专业jn on 班级jn(班级编号jn,专业编号jn)
    课程编号
    create unique index UI_课程编号jn on 课程jn(课程编号jn)
    学生学号,班级编号
    create unique index UI_学号及班级号jn on 学生jn(学生学号jn,班级编号jn)
    学生学号,课程编号
    create unique index UI_学号及课课程号jn on 学习jn(学生学号jn,课程编号jn)
    5.4 触发器建立当删除“教师jn”中的‘教师编号jn’记录时,需要相应地删除“授课jn”和“上课jn”里的“教师编号jn”,所以在“教师jn”上建立触发器:
    create trigger TR_DELETE_教师编号jnON 教师jninstead of deleteas delete from 授课jn from deleted where 授课jn.教师编号jn = deleted.教师编号jn delete from 上课jn from deleted where 上课jn.教师编号jn = deleted.教师编号jn delete from 教师jn from deleted where 教师jn.教师编号jn=deleted.教师编号jn
    当更新“教师jn”中的“教师编号jn”记录时,需要相应地更新“授课jn”和“上课jn”里的“教师编号jn”,所以在“教师jn”上建立触发器:
    create trigger TR_UD_教师编号jnON 教师jnfor update as if update (教师编号jn) begin update 授课jn set 教师编号jn = Ins.教师编号jn from deleted De,inserted Ins ,授课jn K where k.教师编号jn=De.教师编号jnendbegin update 上课jn set 教师编号jn = Ins.教师编号jn from deleted De,inserted Ins ,上课jn K where K.教师编号jn=De.教师编号jnend
    5.5 存储过程建立建立一个输入成绩,自动生成其总学分的存储过程:
    create procedure PRO_输入成绩自动生成学分jn@学生学号jn char(20),@课程编号jn char(20),@课程名jn char(20),@学期jn char(20),@成绩jn int,@教师姓名jn char(20)as begin update 学生jn set 学生jn.已修学分总数jn =学生jn.已修学分总数jn +(select 学分jn from 课程jn where @课程编号jn=课程编号jn ) where 学生jn.学生学号jn=@学生学号jnend
    6、系统简介登陆界面

    进入学生界面

    学生管理-个人信息

    学生管理-课程查询

    学生管理-班级开课

    学生管理-成绩查询

    学生管理-修改密码

    教师登陆


    教师管理-任课查询

    教师管理-查询自己教授不同课程的平均成绩

    教师管理-输入学生成绩

    管理员登陆

    管理员维护-管理教师信息

    管理员维护-管理学生信息

    管理员维护-生源地统计

    7、实验总结7.1 遇到的问题和解决的办法ER图,基本表设计问题
    开始的时候什么都不懂,上课学过的东西虽然朦朦胧胧有些听懂了,不知道如何使用。开始建E-R图的时候,先建好了教师,学生,班级的属性集,但是如何将他们结合起来,却是个大问题.后来与同学交流想明白,教师负责给班级授课,一个教师课上多门课程,一个班级可以选很多课,教师给学生打分时通过课程编号,班级编号,学号来选确定。
    另外加了三张表负责记录登陆时的账号和密码,为什么不把密码这一项加入学生,教师,管理员中呢?
    因为个人觉得密码一项和别的信息联系很少,独立出来更易管理。但是建的基本表越多,冗余和异常就越容易出现。
    SQL视图设计问题
    首先,刚开始写软件是一直是直接连接基本表,以为视图不会用到。但后来要实现复杂功能时,才意识到要用视图来实现,于是后期才实现视图。
    其次,我在设计基本表的时候,为了顾及信息的详细和全面,设计了12张基本表,为后面的设计带来了很大的麻烦。设计视图的时候,因为有很多信息的交叉,还有很多外键,需要很多自然连接 ,非常繁琐。
    触发器和存储过程设计问题
    表示触发器和存储过程上课没怎么讲,自己觉得很高深,一直不敢去动这一方面的设计。后来因为管理员删除教师时,必须要删除关联的‘授课表’,‘上课表’,还有教师输入某个同学成绩时,要同时修改‘学生表’中的‘已修学分总数’。才开始接触这一方面。但是语法还是理解了好久。
    由于前期理解问题,随便写了一个触发器,导致管理员无法正常删除教师,在同学细心指导下,重新写了一个trigger,测试通过。
    触发器:触发器(trigger)是个特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。触发器经常用于加强数据的完整性约束和业务规则等。 触发器可以从 DBA_TRIGGERS USER_TRIGGERS 数据字典中查到。
    存储过程:存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,是利用SQL Server所提供的Transact-SQL语言所编写的程序。经编译后存储在数据库中。存储过程是数据库中的一个重要对象,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是由流控制和SQL语句书写的过程,这个过程经编译和优化后存储在数据库服务器中,存储过程可由应用程序通过一个调用来执行,而且允许用户声明变量 。同时,存储过程可以接收和输出参数、返回执行存储过程的状态值,也可以嵌套调用。
    用NETBENS设计软件
    其实刚开始比较偏爱Eclipse,因为它挑错能力很强,还可以利用快捷键实现代码自动生成。选择NETBEANS是因为同学推荐,支持可视界面设计,自动生成相应代码.显然相比于用代码将组件一个一个的add进panel,这会大大缩短设计时间,但是这些auto-generated-code,冗余度很大,举个例子 javax.swing.JButton;java.awt.event.ActionListener.而这些自动生成的代码不允许用户修改。由于很纠结这一点,于是把代码复制到Eclipse下,自己手动修改这些代码,但是很烦,每改一次界面设计,NetBeans就会重构代码,意味着前面白改了,后来就放弃这种吃力的方法。
    虽然不需要敲很多代码,但是为了让界面布局合理花了好多时间去调组件参数,有时候修改一个组件的参数,相邻的组件都会改变,很复杂。
    实现对jButton,jComboBox的事件监听很方便,只要求把逻辑调对就可以了。
    数据库与NetBeans连接问题
    其实前期一直以为连接数据库很烦,后来在同学指导下学会如何接.Netbeans对数据库支持很好,在netbeans的IDE可以像SQL Server一样登陆数据库D01jiangnan,查看基本表,视图,能实现select,update,delete语句.还有需要配置软件编译时的库文件,必须要把sqljdbc4.jar放到编译库中去(sql server 2008及以上用 sqljdbc.jar文件,sql server 2005 要用sqljdbc,jar).还有连接数据库有两种方式:jdbc或者jtds.
    sql语句撰写问题在调试软件的时候,很多时候都是sql语句写错了,但因为sql类型是String,编译时查不出来,需要运行相关代码时才会报错。
    7.2 系统设计的不足数据库中数据量太少
    在进行数据设计的时候,只考虑了几个最简单的数据输入,可能只能用于应付作业,并不能用于实际。
    界面比较丑
    对于netbean使用比较生疏.而且逻辑上存在问题,修改比较繁琐。
    1 评论 5 下载 2019-05-01 11:59:46 下载需要15点积分
显示 75 到 90 ,共 15 条
eject