版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
摘要随着信息技术的发展,Internet网络技术日渐成熟,人们的交流和沟通也变得极为便捷,动态网络技术应运而生,本文介绍了应用ASP技术的个人博客系统。博客系统主要为用户发表个人意见以及相互交流和交换意见,用户通过网络可以自己撰写文章或者与其他人交流,个人博客系统主要实现了对传统报纸和纸质信件的突破,作为可以进行数字化,网络化,信息化,智能化的文章管理与通信,这是一种全新的交流方式。本系统的开发使用JAVA技术,前端开发使用html,css和JavaScript,在前端后端的连接层使用thymeleaf替换掉了JSP,后端使用SSM,后台使用MYSQL数据库,并通过JDBC进行访问。在部署环境上使用了Windows,使用shiro框架进行权限控制javaMail进行邮件验证,PageHelper分页插件,Swagger接口测试。本文明确用户的需求,进行了可行性分析最后进行系统设计。1,根据模块化管理办法实现不同的系统功能模块。2,在数据库设计模块,保障了数据库设计的安全性与可行性,同时做出了完整性措施。3,程序设计使用面向对象的思路,对前台和后台进行了详细的说明。4,系统测试部分,具体分析了各种情况,分别进行了黑盒测试与白盒测试,分别提出了解决方案,最后对系统进行客观,全面的评价。关键词:JAVA/THYMELEAF;MYSQL;shiro框架目录第1章绪论 11.1问题的提出及研究意义 21.2系统分析 2第2章技术介绍 22.1MYSQL简介 22.2SSM框架介绍 32.3JAVA技术介绍 32.4MyEclipse简介 4第3章需求分析与可行性分析 53.1可行性分析 53.3.1技术可行性 53.3.2经济可行性 53.2业务流分析 63.3需求分析 63.4系统的操作流程 6第4章系统概要设计 74.1系统的总体设计概要 74.2系统的功能结构图 74.3数据库概念结构设计 84.5数据库逻辑结构设计 94.6本章小结 16第5章系统详细设计 165.1登陆注册功能页面与后端代码 165.2注册页面与代码 195.3首页页面与代码 205.4留言页面与代码 265.5全局搜索功能页面与代码 315.6博客详情阅读页面与代码 31第6章系统测试 346.1系统测试的概要 346.2测试内容 346.2.1H模型与W模型组合的单元测试 346.2.2集成测试 356.2.3系统测试 356.2.4验收测试 366.3测试结果 37第7章文章总结 38参考文献 39第1章绪论1.1问题的提出及研究意义博客,是随着互联网技术不断发展应运而生的一种网络通信技术,这个概念首次提出在国内最早于2002年。然而Blog的这个英文词义最早出现于1989年,blog其实是weblog的简称,而weblog其实就是web与log的连写,这也彰显了博客与互联网web技术有着紧密联系。随着时代和当代技术的不断发展,博客技术也开始在人群中普及,影响面逐渐变广。博客的正式名称为网络日记,也就是指使用特定的应用软件,在网络上进行文章的发布或者张贴,它通常是一种由个人管理、不定期张贴新的文章的网站。博客上的文章通常以网员形式出现,并根据张贴时间,以倒序排列。博客是继MSN.BBS.ICQ之后出现的第4种网络交流方式,非常受使用者的喜爱相当于网络时代中的个人的“读者”,它不仅仅代表了一种新的文章发布形式,更代表着一种新的生活方式。一部分博客用户专注于特定的课题和新闻的分析,其他则被比较偏向于个人的日记。一个典型的博客通常会结合文字、图像、其他博客或网站的链接及其它与主题相关的媒体,并且读者可以互动式的留下发言和观点。当然,大部分的博客内容主要以文字为主,但是也有很多的博客专注于摄影、音频等多方面的博客内容。博客在当今时代已经逐渐成为了社交媒体的一种新途径,比较著名的有新浪、网易等博客。在国外研究中比较著名的博客开发平台是GitHub。GitHub是一个面向开源及私有软件项目的托管平台,因为只支持Git作为唯一的版本库格式进行托管,故名GitHub。GitHub于2008年4月10日正式上线,除了Git代码仓库托管及基本的Web管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱、代码片段分享等功能。目前,其注册用户已经超过350万,托管版本数量也是非常之多,其中不乏知名开源项目RubyonRails、jQuery、python等。GitHub去年为漏洞支付了16.6万美元赏金。2018年6月,GitHub被微软以75亿美元的价格收购。GitHub是全球最大的开源软件开发与管理社区,包括Google、Facebook等众多技术巨头也都在这里安营扎寨,GitHub也成为了一探硅谷技术趋势最好的窗口,这个20亿美元的创业公司被开发者称为“全世界最大,最具有研究深度的博客开源软件社区”,每年GitHub都会推出“Octoverse”报告,其中列出了一些趋势以及相关排行榜,比如:在本网站用户中最受欢迎的编程语言。JAVA是最常用的开发语言之一,Java是面向对象的程序设计,不同于以往传统的面向功能的程序设计如C语言,Java编程时不要求编程者详细了解所研究对象的具体细节包括功能、外观、内部结构、各种状态和基本原理等,然后再考虑如何用数据描述它,并设计算法实现各种功能,它只需考虑所研究对象是做什么的,有哪些属性和方法。在模版引擎方面thymeleaf是最受到欢迎而且使用量最大的SpringBoot。Spring官方放弃JSP是因为暂时没有好的解决方案,因为JSP需要本地空间保存JSP引擎动态生成的Servlet类,而SpringBoot程序往往是以Jar的形式脱离容器独立运行,这就需要设置额外的地址去保存,会有安全上的问题,背离了SpringBoot最初设计的目的。而Thymeleaf的标签比较简单,并且它允许前端人员即时查看静态页面的效果,这是FreeMaker或者Velocity等其它模板做不到的功能,这也使得它逐渐成为了一种开发使用的潮流。考虑到横向添加SSR服务很方便,所以效率并不是什么大问题。1.2系统分析本毕业设计的主要内容是研究并创建一个基于Java开发语言和SSM框架的中学生心理测试管理系统,该项目使用的开发语言是今天流行的Java开发语言,THYMELEAF技术被用于设计项目的网页,应用SSM框架技术作为项目开发的整体框架,后端数据库采用MySQL。从而达到系统的规范化、系统化前端:html,css和JavaScript。但是前端和后端的连接层使用thymeleaf以及Jquery的Ajax技术。后端:SSM。数据库:MySQL。部署环境:Windows。其他零散的技术点:shiro框架进行权限控制,JavaMail邮件验证,PageHelper分页插件,Swagger接口测试,Redis数据库,Ajax局部刷新,markdown写作。2.1MySQL简介MySQL是一个简单而方便的SQL数据库操作系统,具有强大的功能和高度的灵活性。它有以下特点:1.高性能且服务稳定,通常情况下极少出现宕机等情况。2.使用成本低。3.大众工具,如果遇到不懂的问题可以在网上进行交流。4.体积小,从而安装起来很方便,适用于一些操作新手,且易于维护。2.2SSM架构技术SSM框架是对SpringMVC,spring,MyBatis三大框架的整体应用,可以提高项目开发的效率,提高方案的维护和开发能力。Spring的MVC设计模式使我们的区域简单而清晰,我们可以编写有条理的程序。在java里面,要用类里面的方法,就需要先有类的对象,而类的对象就是新编写出来的Spring其本质就是用来简化这一步操作的框架。Spring是一个容器,里面装了很多Bean也就是实体对象。之后如果要用到这些对象对应的类的方法,可以直接从Bean里面拿,就不用再去创建一个。SpringMVC是一个控制器和视图分发器的组合体,负责处理业务逻辑层,是最接近用户的东西。当用户在页面做了某个操作,可以理解为发起一个请求,这个请求会被送到SpringMVC这个控制器,根据对于业务逻辑的理解来决定后端要做出什么操作(比如要从数据库增删改查还是展示到前端页面),相当于servlet的功能Spring作为容器框架,使对象与对之间不再需要代码相关联,而是通过其配置类说明,它的核心是AOP,IOC和ID。简单来说,它是一个轻量级的开源框架依赖控制反转,在JAVA开发中可以帮助创建对象,而开发者只需要提供配置文件而且配置文件可以使xml也可以是java本身。当用户在页面做了某个操作,理解为发起一个请求,这个请求会被送到SpringMVC这个控制器,根据对于业务逻辑的理解来决定后端要做出什么操作(比如要从数据库增删改查还是展示什么到前端页面),相当于servlet的功能。MyBatis可以和数据库打交道,是一个对数据库重量级持久的操作。总的来说:页面发送请求给控制器(控制器,进入SpringMVC范围了),控制器调用业务层处理逻辑,逻辑层向持久层发送请求,持久层与数据库交互(就是MyBatis起作用了),后将结果返回给业务层,业务层将处理逻辑发送给控制器,控制器再调用视图展现数据(视图分发器,是SpringMVC起作用)。这个过程中,Spring作为一个容器,将整个过程囊括进去了。1.Spring的优势:通过Spring的IOC特性,将对象之间的依赖关系交给了Spring控制,方便解耦,简化了开发通过Spring的AOP特性,对重复模块进行集中,实现事务,日志,权限的控制。提供了对其他优秀开源框架的集成支持。2.SpringMVC的优势:SpringMVC是使用了MVC设计思想的轻量级web框架,对web层进行解耦,使我们开发更简洁与Spring无缝衔接灵活的数据验证,格式化,数据绑定机制。3.Mybatis的优势:数据库的操作(sql)采用xml文件配置,解除了sql和代码的耦合提供映射标签,支持对象和数据库orm字段关系的映射,支持对象关系映射标签,支持对象关系的组建提供了xml标签,支持动态的sql。
2.3JAVA技术简单来说,它是一种可以实现项目中页面的动态效果。Java技术可以实现页面的动态设计,Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解得多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。2.4MyEclipse简介MyEclipse(MyEclipseEnterpriseWorkbench)常常用来进行各种中小型项目的开发,使用起来方便快捷,这是一个极好的开发工具。使用MyEclipse进行项目的开发可以大大提高开发、应用程序整合的工作效率。总之,MyEclipse是对eclipse软件的二次开发,它集成了许多常用的框架,包含了许多功能,比方说拥有对项目进行调试、测试、完备编码和发布等诸多性能,是一款十分强大的企业级开发工具。第3章需求分析与可行性分析3.1可行性分析系统的可行性研究就是对系统的技术、经济和操作可行性进行分析。3.1.1技术可行性该项目使用的开发语言是今天流行的Java开发语言,THYMELEAF技术被用于设计项目的网页,这种先进的SpringBoots技术完美克服了过去置换型模版引擎效率低下,无法满足高负载应用需求的缺点。应用SSM框架技术作为项目开发的整体框架,后端数据库采用MySQL。从而达到系统的规范化、系统化,因而在技术层面上它是可行的。3.1.2经济可行性在如今的信息时代,通过信息技术的管理既可以减少物力人力,增加效率,还可以使数据更加安全。相比Gihub开发平台在国外创建的类似的博客系统,微软在2015年收购Gihubblog时花费了8900万美元,而这个博客系统在2019年就已经停止运作,。本系统使用的MySql,java,css,html均为免费产品,ajax局部刷新和shiro权限框架均为破解产品,javamail在2011年已经宣布为免费,分页技术在2015年就已经有破解版本,而markdown是电脑自带的软件。因此,本系统在经济上是可行的。综上所述,在技术、经济上本系统都满足条件,所以本系统在开发上是可行的。3.2业务流分析本系统主要分为系统管理员、用户两个权限。管理员可以审阅文章是否违规,对于未违规文章将给予发布许可,文章的作者将可以将文章发布在博客系统中,并且通过全局搜索功能将可以被查询和阅读。而被认定违规的文章将会认定为不可发布,同时管理员通过shiro权限架构可以查看发布文章的用户使用和发布过的言论,如果言论被认为是违规言论,用户将会被封禁,而未违规言论则因为本次的违规文章问题被警告。管理员的业务流程,如图3-3所示。图3-3管理员业务流程用户在主页面后将进入登录页面,通过登录页面的IF语句,已经拥有账号的用户将可以登录进入博客系统,可以进行阅读,评论和发布文章等活动。而未拥有账号的用户将进入注册页面,通过MyBaits连接数据库,经过认证其身份信息属实不违规则可以建立账号,进入博客系统进行与用户相同的活动。而身份信息不属实的用户则不被允许建立账号,只能以游客身份进入,游客不能发布文章。用户的业务流程,如图3-4所示。3-43.3需求分析本系统主要实现个人博客管理系统,项目分为管理员和用户两个权限。系统管理员的功能包括了对注册博客账户的人员进行管理,管理网络言论和文章,可以删除博客中的不良言论,或者禁言用户。系统的管理员有独特的管理员ID,通过登录页面的IF语句,管理员可以登录进入系统,shiro权限架构则保证了只有管理员可以进入后台页面,可以在后台页面行使系统管理员的功能。图3-1系统管理员用例图注册用户在完成注册后,需要绑定自己的身份信息,身份信息是绝对保密的,用户可以在博客中回答或者提出问题,可以发表带有自己想法的文章,也可以点赞或者举报其他人的文章。注册用户因为没有在shiro框架下匹配的IF语句,注册用户和游客都无法进入后台页面。用户在登陆后进入主业页面,从主业页面可以前往阅读页面和全局搜索页面,行使其回答问题,提出问题,发表文章,点赞文章,举报和完善个人信息的功能。图3-2注册用户用例图(1)注册登录功能:用户可以注册并个人博客系统。(2)提出问题:用户可以提出问题。(3)回答问题:用户可以回答问题。(4)文章发表:用户可以发表文章或者点登录评其他人的文章。(5)个人信息完善:用户可以完善个人信息。3.4系统的操作流程系统业务的流程步骤是:首先输入网址后进入登录界面,用户要注册成功后才能登录首页,进行评论或者上传文件,在首页可以通过分页ajax技术前往三个不同的页面:回到登录页面切换账号或者更改个人信息。前往阅读页面进行全局阅读。前往全局搜索页面,可以搜索数据库内所有的内容。第4章系统概要设计4.1系统总体的设计概要本系统的设计目的就是创建一个能够符合平民阶层,通易懂简洁而高效的个人博客系统,力图在更大范围内普及blog这样的网络概念,这能够极大的方便边远地区和低教育层次的人们的交流与沟通,并赋予他们更简洁的娱乐和知识获取途径。1.界面简单大方,用户更加操作起来更加方便。2.实现测试功能,从而达到用户的需求。3.实现对数据库的数据录入。4.2系统的功能结构系统功能包括:1,前台页面博客文章展示功能。2,登录、注册、注销、管理员登录功能。3,管理员进入后台管理博客,设置博客置顶、删除评论等功能。4,游客登录及评论功能。5,上传文件功能。6,阅读页面阅读文章功能。7,全局搜索页面搜索内容的功能。4.3数据库概念结构设计项目包含实体有:管理员实体、用户实体、文章实体、各个实体的具体描述实体属性关系图如下:1.管理员包括删除和更改文章与回答,封禁用户,管理员实体和属性的关系图如图4-3所示。图4-3管理员实体图2.用户实体包括ID,身份信息,是否删除自己发布的文章和问题,提出问题,回答问题等属性。用户实体和属性的关系图如图4-4所示。图4-4用户实体图3.文章实体包括文章ID,时间,发布人或发布机构,介绍,标题,内容等属性。文章实体和属性的关系图如图4-5所示。图4-5文章实体图4.5数据库逻辑结构设计本系统采用MySQL数据库存储数据,系统中使用到的主要数据表有:blog_type,t_admin,t_blog,t_comment,t_friend,t_message,t_picture,t_type,user。表4-1类型表(blog_type)4-2(t_admin)名称类型空备注IdAvatarCreate_timeEmailNicknamePasswordTypeUpdate_timeadminnameBigintVarcharDatetimeVarcharVarcharIntDatetimevarchar主键头像创建时间邮箱地址昵称密码所属类型更新时间管理员名称表4-3博客用户表(t_blog)名称类型空备注IdAppreciationCommentabledContentCreate_timeAdscriptionFirat_pictureFlagPubliahedRecommendAhare_statementTitleUpdate_timeVievaType_idAdmin_idComment_countIntBitBitLongtextDatetimeVarcharVarcharVarcharBitBitBitVarcharDatetimeIntBigintBigintint主键升值反对内容创建时间归属图片标记已发布推荐声明标题更新时间观察类型ID管理员ID评论总数表4-4评论表(t_comment)名称类型空备注IdBicknameEmailContentAvatarCreate_timeParent_comment_idAdmin_commentblogIdIntVarcharVarcharVarcharVarcharDatetimeIntBitint主键昵称邮箱内容匿名创建时间相关内容ID管理内容博客ID表4-5好友表(t_friend)名称类型空备注IdBlogaddressBlognameCreate_timepictureaddressBigintVarcharVarcharDatetimevarchar主键ID博客地址博客名称创建时间图片源表4-6消息表(t_message)名称类型空备注IdNicknameEmailContentAvatarCreate_timeParent_message_idAdmin_messageBigintVarcharVarcharVarcharVarcharDatetimeBigintbit主键昵称邮箱内容匿名创建时间相关消息ID管理内容4.7图片表(t_picture)4.6本章小结本章主要介绍了项目的实现目标、数据库的概念设计和逻辑设计,主要包括对每个功能的实体图以及全局流程。通过数据库中的表可以获得海量的内容来源,再通过MyBaits技术被发往后端,最终被前端调用。数据库是博客系统获得数据的来源,通过数据库设计使得博客中的文章,评论和阅读内容时刻保持生命力。第5章系统详细设计本系统按照用户的需求,主要实现以下几种功能:管理员和用户可以实现登录注册功能,包括管理员对前台页面博客文章展示功能。用户的登录,注册,注销功能。管理员的登录功能。后台管理博客,设置博客置顶,删除评论等功能。游客登录及评论功能。上传文件的功能。5.1.登录页面和后端代码图5.1主页面在点击EnterBlog会进入主页。图5.2.1用户登录页面图5.2.2管理员登录页面用户的登录需要使用IF语句,当输入用户名与密码对应才能登入账号。登录页面分为两部分,管理员的登录和用户的登录。都需要使用IF语句。@RequestMapping("/login")//这里的@RequestParam("username")是从前端(index.html)里面接收传来的参数(字段名为name的属性,会传过来.publicStringlogin(@RequestParam("email")Stringemail,@RequestParam("pwd")Stringpwd,Modelmodel,HttpSessionsession){Useruser=userService.getUserByEmail(email);//获取主体对象Subjectsubject=SecurityUtils.getSubject();try{subject.login(newUsernamePasswordToken(email,pwd));System.out.println(user.getNickname()+",欢迎您登陆成功!");session.setAttribute("logineduser",user);return"redirect:/article";}catch(UnknownAccountExceptione){e.printStackTrace();model.addAttribute("loginerror","用户名错误");}catch(IncorrectCredentialsExceptione){e.printStackTrace();System.out.println("密码错误");model.addAttribute("loginerror","密码错误");}return"login";/*Useruser=userService.getUserByEmail(email);//如果该用户存在而且密码正确而且被激活了那么就让他登录if(user!=null&&user.getPwd().equals(pwd)&&user.getStatus()==1){//回显欢迎信息System.out.println(user.getNickname()+",欢迎您登陆成功!");*//*添加一个属性,就是已经登录了的对象.这里非常重要,这就是model.addAttribute传对象的操作.在index.html里面有对它的接收*//*model.addAttribute("logineduser",user);//这里最好是登陆成功返回一个新的页面不过我没写暂时还是index到新的页面去就可以注销了,而且登陆和注册按钮都没了return"index";}else{if(user==null){System.out.println("用户名错误");model.addAttribute("loginerror","用户名错误");}elseif(user.getStatus()!=1){System.out.println("您的账号未激活或被冻结,请联系客服");model.addAttribute("loginerror","您的账号未激活或被冻结,请联系客服");}else{System.out.println("密码错误");model.addAttribute("loginerror","密码错误");}return"index";}*/}图5.1.3管理员登录界面5.2.注册页面和代码使用JavaMail和图形验证码,注册用户会收到javamail邮件或者图形验证码如图5.2图5.2图形验证码可以看不清楚换一张,使用技术awt绘图。5.3.主页页面和代码图5.3主页页面在图5.1主页面点击EnterBlog就会进入主页页面,在登陆之前可以以游客身份登录。而点击右上角的登录页面可以回到图5.2的登录页面进行用户登录。主页页面分为三部分,回到登录页面,进行全局搜索和阅读页面。图5.2.1首页底端使用了pagehelper首页的分页查询。代码如下://去分类管理页面@GetMapping("/types")publicStringtoTypes(Modelmodel,@RequestParam(defaultValue="1",value="pageNum")IntegerpageNum){/*PageHelper分页插件:官方文档:https://pagehelper.github.io/docs/StringorderBy="字段名排序规律";PageHelper.startPage(pageNum,pageSize,orderBy);*/StringorderBy="iddesc";PageHelper.startPage(pageNum,8,orderBy);List<Type>list=typeService.queryAllTypes();//用PageInfo对结果进行包装PageInfo<Type>pageInfo=newPageInfo<Type>(list);System.out.println(pageInfo);model.addAttribute("pageInfo",pageInfo);return"admin/types";}在阅读的文章详情页面,文章源自于数据库博客文章的标题,内容,和博客图片链接,首先从数据库中取得然后会使用MyBatis技术,之后数据库中的数据通过DAO层,进入service层。然后后端就可以拿到从数据库中取得的数据,将其回显给前端。通过SpringMVC的ModelAndView回到前端,前端再使用thymeleaf技术进行接收。基本所有的页面都是采用的数据库数据进入后端在回到前端。其后端代码如下:@GetMapping("/article")publicStringtoArticle(Modelmodel,RedirectAttributesattributes,@RequestParam(defaultValue="0",value="startIndex")intstartIndex){//指定每页容量intpageSize=8;HashMap<String,Integer>pageMap=newHashMap<String,Integer>();pageMap.put("startIndex",startIndex);pageMap.put("pageSize",pageSize);//根据前端传入的startIndex和指定的每页容量,分页查询List<BlogQuery>blogQueries=blogService.queryAllBlogByLimit(pageMap);if(blogQueries.size()==0){System.out.println("查不出来了!到最后一页了。后期给用户回显一个提示:到最后一页了哦");attributes.addFlashAttribute("negativeMessage","已经是最后一页了哦");return"redirect:/article?startIndex="+(startIndex-pageSize);}//将查出来的分页数据回显给前端model.addAttribute("blogQueries",blogQueries);//下面两个东西,是为了辅助前端校验上一页和下一页合法性,比如是否越界等model.addAttribute("recentStartIndex",startIndex);model.addAttribute("pageSize",pageSize);//下面的东西是为了回显前端共几页共多少篇博客inttotalBlogs=blogService.getBlogsCount();model.addAttribute("totalBlogs",totalBlogs);//共多少篇博客inttotalPages=(totalBlogs%pageSize==0?totalBlogs/pageSize:totalBlogs/pageSize+1);//通过共有多少篇博客和页码容量,算出总页数。并不难model.addAttribute("totalPages",totalPages);//共几页//分类列表传递到前端List<Type>typeList=typeService.queryAllTypes();model.addAttribute("types",typeList);//热门文章列表传递给前端(浏览量最高的8篇热文)List<BlogQuery>hotArticle=blogService.queryAllBlogOrderByViews();model.addAttribute("hotArticle",hotArticle);//置顶推荐模块List<BlogQuery>recommendBlogs=blogService.queryAllRecommendBlog();model.addAttribute("recommendBlogs",recommendBlogs);return"article";}//浏览某分类下的全部博客(分类浏览)@GetMapping("/article/type/{id}")//这里的id和下面的路径变量id冲突吗?不冲突publicStringclassifiedBrowsing(@PathVariableintid,Modelmodel,@RequestParam(defaultValue="0",value="startIndex")intstartIndex,RedirectAttributesattributes){//这个typeId,出现在article-type.html里面的上一页和下一页。到article-type.html里看就懂了//为了解决这里的问题,我还写了一篇博客:/weixin_44757863/article/details/110797979model.addAttribute("typeId",id);//指定每页容量intpageSize=8;HashMap<String,Integer>pageMap=newHashMap<String,Integer>();pageMap.put("startIndex",startIndex);pageMap.put("pageSize",pageSize);//根据前端传入的startIndex和指定的每页容量,分页查询List<BlogQuery>blogQueries=blogService.searchByTitleOrType(newSearchBlog(id),pageMap);if(blogQueries.size()==0){System.out.println("查不出来了!到最后一页了。后期给用户回显一个提示:到最后一页了哦");attributes.addFlashAttribute("negativeMessage","已经是最后一页了哦");//attributes.addFlashAttribute("negativeMessage","别点啦,已经是最后一页了");return"redirect:/article/type/"+id+"?startIndex="+(startIndex-pageSize);}//将查出来的分页数据回显给前端model.addAttribute("blogQueries",blogQueries);//下面两个东西,是为了辅助前端校验上一页和下一页合法性,比如是否越界等model.addAttribute("recentStartIndex",startIndex);model.addAttribute("pageSize",pageSize);//下面的东西是为了回显前端共几页共多少篇博客inttotalBlogs=blogService.getSearchByTitleOrTypeCount(newSearchBlog(id));model.addAttribute("totalBlogs",totalBlogs);//共多少篇博客inttotalPages=(totalBlogs%pageSize==0?totalBlogs/pageSize:totalBlogs/pageSize+1);//通过共有多少篇博客和页码容量,算出总页数。并不难model.addAttribute("totalPages",totalPages);//共几页//分类列表传递到前端List<Type>typeList=typeService.queryAllTypes();model.addAttribute("types",typeList);//热门文章列表传递给前端(浏览量最高的8篇热文)List<BlogQuery>hotArticle=blogService.queryAllBlogOrderByViews();model.addAttribute("hotArticle",hotArticle);//置顶推荐模块List<BlogQuery>recommendBlogs=blogService.queryAllRecommendBlog();model.addAttribute("recommendBlogs",recommendBlogs);return"article-type";}//阅读某博客@GetMapping("/article/read/{id}")publicStringtoRead(@PathVariableintid,Modelmodel){//ShowBlogblogById=blogService.getBlogById(id);//Markdown格式化在这里应用。调用了一个service层的方法ShowBlogblogById=blogService.getAndConvert(id);//浏览量++blogService.updateBlogViews(blogById.getId());model.addAttribute("blog",blogById);/*随机生成延伸阅读模块的文章由于id是不连续的(中间有缺号现象),所以不保证能查询到有效id下面的死循环,可以保证查询到有效id(查不到有效的就一直循环下去了)*/StringblogTitle;intRandomId;while(true){//公式:(数据类型)(最小值+Math.random()*(最大值-最小值+1))下面意思是1到50的随机数后期文章多了可以调大一点RandomId=(int)(1+Math.random()*(50-1+1));blogTitle=blogService.getBlogTitleById(RandomId);if(blogTitle!=null)break;}//将随机到的文章标题和id回传给前端//共有3篇文章,所以传三个标题(其实只有第一个标题是随机的,另外两个标题是它相邻的两个id查出来的标题)model.addAttribute("blogTitle",blogTitle);model.addAttribute("blogTitle2",blogService.getBlogTitleById(RandomId+1));model.addAttribute("blogTitle3",blogService.getBlogTitleById(RandomId+2));model.addAttribute("RandomId",RandomId);return"read";}5.4.留言页面和代码图5.4留言页面使用ajax局部刷新技术。可以在不刷新全页面的情况下局部刷新部分页面。ajax需要部分前后端代码结合。ajax前端核心代码如下:functionpostData(){//使用ajax的方式向Controller提交表单$("#comment-container").load("[[@{/message/load}]]",{"parentMessageId":$("[name='parentMessage.id']").val(),"nickname":$("[name='nickname']").val(),"email":$("[name='email']").val(),"content":$("[name='content']").val()},function(responseTxt,statusTxt,xhr){//回调函数//提交表单之后,调用clearContent()方法会清理掉之前表单填写的东西clearContent();});}//清理掉之前表单填写的东西(还表单一个初始状态,方便下次输入)functionclearContent(){$("[name='content']").val('');$("[name='parentMessage.id']").val(-1);$("[name='content']").attr("placeholder","请输入留言信息...");}后端核心代码如下://该方法负责局部刷新read页面的评论区@GetMapping("/message/load")publicStringmessage(Modelmodel){//把该博客旗下的所有评论都给查出来,封装成一集合,并传到前端去List<Message>messages=commentService.listMessage();for(Messagemessage:messages){System.out.println(message);}model.addAttribute("messages",messages);return"message::messageList";}//在read页面,提交评论表单,点击发布按钮走的post方法@PostMapping("/message/load")publicStringmessagePost(Messagemessage,HttpSessionsession){Useruser=(User)session.getAttribute("logineduser");//从session里拿user的登陆信息message.setAvatar(user.getAvatar());//得到user的头像message.setAdminMessage(false);if(user.getEmail().equals("1134107721@"))//如果检测到是博主登陆message.setAdminMessage(true);//是Admin评论,设置为truecommentService.saveMessage(message);//redirect到上面那个局部刷新的方法return"redirect:/message";}5.5后台管理首页和代码图5.5后台管理页面进入后台需要权限,如果不是管理员就无法进入。通过shiro权限框架可以设置只有输入管理员的用户名和密码才可以进入后台,通过shiro进行进行权限控制以进入后台。shiro核心代码如下:5.6全局搜索功能代码图5.6全局搜索5.8.博客详情阅读页面代码图5.8.1博客详情阅读页面与留言页面类似使用ajax局部刷新技术。图5.8.2博客详情阅读页面的评论页面博客详情阅读页面核心代码如下://阅读某博客@GetMapping("/article/read/{id}")publicStringtoRead(@PathVariableintid,Modelmodel){//ShowBlogblogById=blogService.getBlogById(id);//Markdown格式化在这里应用。调用了一个service层的方法ShowBlogblogById=blogService.getAndConvert(id);//浏览量++blogService.updateBlogViews(blogById.getId());model.addAttribute("blog",blogById);/*随机生成延伸阅读模块的文章由于id是不连续的(中间有缺号现象),所以不保证能查询到有效id下面的死循环,可以保证查询到有效id(查不到有效的就一直循环下去了)*/StringblogTitle;intRandomId;while(true){//公式:(数据类型)(最小值+Math.random()*(最大值-最小值+1))下面意思是1到50的随机数后期文章多了可以调大一点RandomId=(int)(1+Math.random()*(50-1+1));blogTitle=blogService.getBlogTitleById(RandomId);if(blogTitle!=null)break;}//将随机到的文章标题和id回传给前端//共有3篇文章,所以传三个标题(其实只有第一个标题是随机的,另外两个标题是它相邻的两个id查出来的标题)model.addAttribute("blogTitle",blogTitle);model.addAttribute("blogTitle2",blogService.getBlogTitleById(RandomId+1));model.addAttribute("blogTitle3",blogService.getBlogTitleById(RandomId+2));model.addAttribute("RandomId",RandomId);return"read";}第6章系统测试进行系统测试是整个设计的最后一步流程,测试的结果可以反映项目的完备程度,可以根据测试结果找到存在的问题,所以是十分重要的一步。6.1系统测试的目的软件测试是为了检测项目的工程质量,项目功能实现的情况,是否达到了预期的目标。第二是在规定的条件下对程序进行操作,用于发现程序的漏洞,并对是否满足客户需求进行评估。第三是根据客户的需求,通过软件测试系统检测是否正常运行,功能的实现与否直接决定了该项目的质量,通过相应的指令检验完成情况,系统界面的实现是否达到了目标,所以必须认真进行,认真对待。我们将采用单元测试,接口测试,系统测试,验收测试来满足用户的质量需求。6.2测试内容6.2.1H模型和W模型组合的单元测试单元测试具有以下优点:便于后期重构。单元测试可以为代码的重构提供保障,只要重构代码之后单元测试全部运行通过,那么在很大程度上表示这次重构没有引入新的BUG,当然这是建立在完整、有效的单元测试覆盖率的基础上。优化设计。编写单元测试将使用户从调用者的角度观察、思考,特别是使用TDD驱动开发的开发方式,会让使用者把程序设计成易于调用和可测试,并且解除软件中的耦合。文档记录。单元测试就是一种无价的文档,它是展示函数或类如何使用的最佳文档,这份文档是可编译、可运行的、并且它保持最新,永远与代码同步。具有回归性。自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地地快速运行测试,而不是将代码部署到设备之后,然后再手动地覆盖各种执行路径,这样的行为效率低下,浪费时间。H模型将测试活动分离出来,形成一个完全独立的流程,将测试准备活动和测试执行活动清晰地体现出来。如图6.1图6.1H模型提倡者认为测试是一个独立的过程中,所以在H模型中并没有看到关于开发的过程,而是测试的一个流程,当然这个测试的流程并不像V模型和W模型那样有明确的测试区分。H模型演示了在整个生命周期中某个层次上一次软件测试的“微循环”。当测试条件准备完成,进入测试就绪状态后,所在测试H模型中有一个测试就绪点,也就是测试有一个准入条件。通常情况下判断测试是否达到准入条件,应该检查以下几部分内容是否已经完成:该开发流程对应的测试策略是否完成;测试方案是否完成;测试用例是否完成;测试环境是否搭建好;相关输入件、输出件是否明确。也就是说,必须要检查上面一些内容是否完成,再确定我们是否需要进入下一个阶段的测试。当测试条件成熟,并且测试准备工作已经完成,进入了测试就绪点,测试执行活动才可以进行。H模型中还有一个“其他流程”的测试,这个观点强调了测试其他不一定要是常见的应用程序也可以其他的内容,这可以理解为整个产品包中所有的对象,包括开发阶段的一些设计流程,这样将测试的范围直接扩展到整个产品包,而非W模型中提到的代码、需求或其他相关说明书。与V模型和W模型不同的是,H模型的核心是将软件测试过程独立出来,并贯穿产品的整个生命周期,与开发流程并行进行,不需要等到程序全部开发完成才开始执行测试,这充分体现了软件测试要尽早准备、尽早执行的原则。不同的测试活动可以按照某个次序先后进行,当一次测试工作后产品质量无法达到要求时,可以反复进行多次测试。总之H模型具有以下特征:(1)测试是一个独立的过程;(2)测试达到准入条件,才可以执行;(3)测试对象是整个产品包,而不仅仅是程度、需求或相关说明书。由于V模型存在一些明显的缺陷,人们就在实际测试过程中对V模型进行了改进,将V模型演变为W模型。W模型由Evolutif公司提出,由两个V字型模型组成,相对于V模型,W模型增加了软件各开发阶段中应同步进行的验证和确认活动。W模型也称之为双V模型,一个V是开发的生命同期,另一个V是测试的生命周期,W模型与V模型有一个很大的不同,就是W模型是一个并行的模型,V模型是一个串行的模型,W模型开始是从需求分析开始就开始了,而不是等到编码完成后才开始。并且测试阶段的划分更清楚,而不仅仅是单元测试、集成测试、系统测试,还包括前期的测试计划、测试方案等内容,这更符合现在企业测试的流程。W模型强调测试伴随着整个软件开发周期,而且测试的对象不仅仅是程序,需求、设计等同样要测试,也就是说,测试与开发是同步进行的。W模型有利于尽早全面地发现问题。从需求分析开始测试工程师就参与到项目的测试中,当需求分析完成后,测试工程师就需要参与到需求的验证和确认活动中,并需要提供可测试性需求分析说明书,这样可以尽早地发现需求阶段的缺陷。同时,对需求的测试也有利于及时了解项目难度和测试风险,及早制定应对措施,这将显著减少总体测试时间,加快项目进度。但W模型也存在局限性,需求、设计、编码等活动被视为是串行的,同时,测试和开发活动也保持着一种线性的前后关系,上一阶段完全结束,才可正式开始下一阶段工作,这样就无法支持迭代的开发模型。W模型具有以下特征:(1)测试阶段划分得更全面,不仅仅是单元测试、集成测试和系统测试;(2)测试与开发是并行的,从需求测试就应该开始介入;(3)提出尽早测试的概念,这样可以降低缺陷修复成本;(4)测试对象不仅仅是程序,还包括需求或其他的相关文档。使用H模型和W模型的组合。将测试工作从程序设计中独立出来,与编码,设计和分析同步进行,只需要反复进行测试,在只有一个测试条件成熟的情况下,我们就可以进行测试。单元测试流程如下:(1)单元测试进入条件:1.单元时间到达2.被测试软件版本具备3.被测试软件/系统调试通过4。测试物理资源分配到位/测试环境分配到位测试人员到位.(2)单元测试推出条件:1.按照指定溺试需求完成单元测试(除遗留软件外)2.缺陷等级轰级的缺陷修正率达到100%3.缺陷等级B级的缺陷修正率达到100%4.缺陷等级C级的缺陷修正率达到95%5。缺陷等级在C级下的缺陷修正率达到90%6。测试相关文档编写齐全并且评审通过,以下三种文献必不可少:1)单元测试测试用例报告2)单元测试测试缺陷报告3)单元测试缺陷跟踪及回归测试记录文档4)单元测试测试执行记录5)单元测试总结报告6.2测试图1单元测试中,我们对编码进行静态分析。找出一些错误或者收集部分数据,为了进行动态分析,我们运行程序并进行代码分析,对程序运行执行跟踪,对运行结果进行分析。6.2.2集成测试因为单元测试不能反映在集成时的工作状况,单元模块可有正常运行,但是在集成中无法工作的情况时有发生,因此在下一步进行集成测试。集成测试也叫组装测试、联合测试、子系统测试或部件测试。集成测试是在单元测试的基础上,将所有模块按照概要设计要求组装成为子系统或系统。(2)集成测试的关注点:1.在把各个模块连接起来时,穿越模块接口的数据是否会丢失。2.各个子功能组合起来,能否达到预期的要求的父功能。3.一个模块的功能是否会对另一个模块的功能产生不利的影响。4.全局数据结构是否有问题,会不会被异常修改。5.单个模块的误差积累起来,是否会放大,从而达到不可接受的程度。(3)集成测试的模式:①非增殖式集成方式。先分别测试每个模块,再把所有模块按设计要求一次全部组装起来所要的系统,然后进行整体测试。使用这种方式可能发现一大堆错误,但为每个错误定位和纠正非常困难,并且在改正一个错误的同时又可能引入新的错误,新旧错误混杂,更难断定出错的原因和位置。②增殖式集成方式。首先对一个个模块进行模块测试,然后将这些模块逐步组装成较大的系统,在组装的过程中边连接边测试,以发现连接过程中产生的问题。最后通过增殖逐步组装成为要求的软件系统。常用的增殖方法有:自顶向下集成测试、自底向上集成测试、核心集成测试等。自顶向下的增殖方式:将模块按系统程序结构,沿控制层次自顶向下进行集成。由于这种增殖方式在测试过程中较早地验证了主要的控制和判断点。在一个功能划分合理的程序结构中,判断常出现在较高的层次,较早就能遇到。如果主要控制有问题,尽早发现它能够减少以后的返工。自底向上的增殖方式:从程序结构的最底层模块开始组装和测试。因为模块是自底向上进行组装,对于一个给定层次的模块,它的子模块(包括子模块的所有下属模块)已经组装并测试完成,所以不再需要桩模块。在模块的测试过程中需要从子模块得到的信息可以直接运行子模块得到。自顶向下增殖的方式和自底向上增殖的方式各有优缺点。自顶向下增殖方式的缺点是需要建立桩模块。要使桩模块能够模拟实际子模块的功能将是十分困难的。同时涉及复杂算法和真正输入/输出的模块一般在底层,它们是最容易出问题的模块,到组装和测试的后期才遇到这些模块,一旦发现问题,导致过多的回归测试。而自顶向下增殖方式的优点是能够较早地发现在主要控制方面的问题。自底向上增殖方式的缺点是“程序一直未能做为一个实体存在,直到最后一个模块加上去后才形成一个实体”。就是说,在自底向上组装和测试的过程中,对主要的控制直到最后才接触到。但这种方式的优点是不需要桩模块,而建立驱动模块一般比建立桩模块容易,同时由于涉及到复杂算法和真正输入/输出的模块最先得到组装和测试,可以把最容易出问题的部分在早期解决。此外自底向上增殖的方式可以实施多个模块的并行测试。核心集成测试:核心系统先行集成测试法的思想是先对核心软件部件进行集成测试,在测试通过的基础上再按各外围软件部件的重要程度逐个集成到核心系统中。每次加入一个外围软件部件都产生一个产品基线,直至最后形成稳定的软件产品。核心系统先行集成测试法对应的集成过程是一个逐渐趋于闭合的螺旋形曲线,代表产品逐步定型的过程。③混合增殖式测试就是把模块按系统程序结构,沿控制层次自顶向下进行集成和把按程序模块结构的最低层的模块开始集成和测试混合使用。集成测试流程图如图26.2测试图2集成测试需要注意的问题:1)各模块连接应紧密结合,确保变量传递过程中不会丢失;2)各模块组合起来后,能够达到预期要求;3)一个模块不会对另一个模块的运行产生计划外的影响,应保持自己的独立性;4)全局数据结构是否有问题;5)各个模块的误差累积不能超出总误差所允许的极限。6.2.3系统测试系统测试是针对整个产品系统进行的测试,目的是验证系统是否满足了需求,找出与需求规格不相符合或与之矛盾的地方,并检查出程序中存在的错误,提高系统的可靠性,其流程如下制订测试计划—设计测试用例—执行系统测试—缺陷管理与改错再由缺陷管理与改错迭代到执行系统测试。需要分别进行功能测试,健壮性测试,性能测试,用户界面测试和安全性测试。6.2.4验收测试验收测试;需要分别进行由公司内部人员模拟用户进行的α测试和软件公司所组织的用户进行的β测试。6.3本章小结在本章中讨论了软件测试,通过单元测试,集成测试,系统测试和验收测试列出了测试所经过的流程。单元测试是本文主要侧重的测试点,单元测试对我们的产品质量是非常重要的。单元测试是所有测试中最底层的一类测试,是第一个环节,也是最重要的一个环节,是唯一一次有保证能够代码覆盖率达到100%的测试,是整个软件测试过程的基础和前提,单元测试防止了开发的后期因bug过多而失控,单元测试的性价比是最好的。据统计,大约有80%的错误是在软件设计阶段引入的,并且修正一个软件错误所需的费用将随着软件生命期的进展而上升。错误发现的越晚,修复它的费用就越高,而且呈指数增长的趋势。作为编码人员,也是单元测试的主要执行者,是唯一能够做到生产出无缺陷程序这一点的人,其他任何人都无法做到这一点:包括:代码规范、优化,可测试性的代码,放心重构自动化执行three-thousandtimes。根据微软的统计数据:bug在单元测试阶段被发现,平均耗时3.25小时,如果漏到系统测试阶段,要花费11.5小时。参考文献[1]李洋.SSM框架在Web应用开发中的设计与实现[J].计算机技术与发展,2016,(12):190-194.
[2]蒋启明,彭小宁,张文.“轻量级JavaEE”课程的Spring框架教学改革探讨[J].科教文汇(中旬刊),2016,(11):57-58.
[3]马杰川.基于THYMELEAF的企业Blog系统的设计与实现[D].电子科技大学,2013.
[4]韦耿,钟亮.基于THYMELEAF的个人博客系统[J].电脑知识与技术,2013,(21):4865-4869+4876.
[5]杨嘉群.基于THYMELEAF的博客系统[J].电子制作,2013,(09):68-69+32.
[6]祁新安,李凯.基于THYMELEAF的多媒体博客系统的研究[J].电脑开发与应用,2013,(04):33
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 护理服务:提升患者体验的秘诀
- 护理研究创新性评估的评估机制创新
- 西式厨师证初级实务题库及答案
- 工资转帐协议书
- 委托投资款协议书
- 2026年人教版科学三年级下册期中测试卷(含答案)
- 重力势能课件2025-2026学年高一下学期物理人教版必修第二册
- 2022年部编版八年级语文上册期中考试及答案【各版本】
- 直线与直线平行课件2025-2026学年高一下学期数学人教A版必修第二册
- 2026年小区雨水管网改造承包合同协议
- 2026版公司安全生产管理制度及文件汇编
- 2026年中国铁路各局集团招聘试题及答案解析
- 湖北省2026届高三(4月)调研模拟考试 英语答案
- 工厂质量管理奖惩制度模板
- 含蜡原油管道蜡沉积与清管
- 【超星尔雅学习通】商法的思维网课章节答案
- 磁悬浮离心冷水机组、螺杆式水冷冷水机组、离心式水冷冷机组及多联机组方案比较
- JJF 1319-2011傅立叶变换红外光谱仪校准规范
- 高数下册试题及答案
- 蓄热步进式加热炉设计说明书
- 质量保证体系架构图
评论
0/150
提交评论