JAVA SMART系统-系统框架设计与开发

news2025/1/23 12:55:13

       SMART系统是一个新型智能在线考试信息管理系统,该系统主要实现了学生在线考试与评估以及教师对学生在线考试信息的管理和维护。本文按照SMART系统的非功能性需求,基于Struts、Spring、Hibernate三种开源技术,构建了一个具有良好的可扩展性、可维护性、可靠性的系统框架。整个系统的框架分为三层,分别为表现层、业务层和持久层。 本系统的表现层是基于Struts作扩展设计,结合本系统的需求完成了自定义标签的封装,基本action接口的编写。在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库操作的封装。这样设计减少了耦合性且避免了生成大量的临时对象。

该系统框架能达到良好的可拓展性和维护性。它不仅仅适用这个系统的开发,可以应用于J2EE领域中基于SSH来架构的大部分B/S系统。

如图1所示,在整个SMART系统的总体框架中表现层是结合J2EE领域的开源框架Struts来实现的,Struts能充分满足应用开发的需求,简单易用,该框架是基于MVC模式的来构建的,该模式将表达层分解为自包含的和可重用的几个部分,当用户通过浏览器发起HTTP请求时,该框架将利用其ActionForm将请求页面的非对象化的数据转化为对象,交由其对应Action来处理。基于MVC模式的整个交互的序列图如图7所示:

开发人员利用该框架进行开发时,不用再自己实现全套MVC模式,节省了大量的开发时间。

  1. 业务层

如图1所示,在表现层与业务层之间利用一个公共代理类来完成交互,该代理类采用单例模式设计开发,在整个框架中起到了如下几点作用:

  1. 减少耦合性
  2. 避免生成大量的临时对象

在该代理类,实现一个对相应业务逻辑的处理方法,该方法的参数为一个封装好相应的页面数据对象、要调用的业务类的名称及该业务类中相应的处理方法名的类。

在该层中利用了Spring框架中的IoC模式(英文全名为Inversion of Control即反转模式),该模式类似于著名的好莱坞原则:“Don't call us,we'll call you”,后被Martin Fowler改名为 Dependency Injection 依赖注射,也就是将类之间的关系通过第三方进行注射,不需要类自己去解决调用关系,实现了调用者和被调用者之间的解耦分离。IoC的引入并没有消除接口与实现类之间的联系,它的实质在于只是将这种联系转移了。在Spring的IoC实现中这关系被转移到相应的XML配置文件中,由Spring框架来提供对这种关系的依赖注入。其原理如图8所示:

  1. 持久层

在SMART系统的整体框架中的持久层,是采用基于现有持久层框架的实现模式,在这种模式中,将最为繁琐的基于JDBC的OR映射工作,交由第三方组件(本框架中采用开源的Hibernate)来完成,这样就会在对数据访问对象进行编码时,大大的简化了一些繁琐而又复杂的编码工作,只需要利用Hibernate提供的API,对持久化对象进行操作。在该持久层框架提供了优秀的性能优化机制,如内置的数据库连接池支持,PreparedStatement缓存、数据缓存等。这些优化机制的综合使用大大提升了系统的性能。

在SMART系统的持久层中,对一些常用的添加、删除、更新数据库操作进行了抽象封装。并在Hibernate中配置相应的数据库连接池实现。

  1. 总体结构设计与建模
  2. 公共代理机制的设计

在大部分采用B/S结构的web应用中,用户与系统的交互都是要涉及到相应的交互数据、业务逻辑,因此在本系统的框架设计中考虑到将这些交互中涉及到的因素全部封装到一个Carrier类中,再通过一个单例类来实现表现层与业务层的交互,这样用户操作时不用每次都去new一个临时的对象,也实现各功能模块中子程序之间的解耦。

  1. 系统接口设计

Java程序设计语言提供了两种机制,可以用来定义一个允许多个实现的类型:接口和抽象类。两种机制之间最明显的区别是,抽象类允许包含某些方法的实现,但是接口是不允许的。一个更为重要的不同之处在于,为了实现一个由抽象类定义的类型,它必须成为抽象类的一个子类。任何一个类,只要它定义了所有要求的方法,并且遵守通用约定,那么它就允许实现一个接口,不管这个类位于类层次的哪个地方。因为Java只允许单继承,所以,抽象类作为类型定义受到了极大的限制。接口使得我们可以构造出非层次结构的类型框架。例如:假设有一个接口代表一个singer(歌唱家),另一个接口代表一个songwriter(作曲家):

public interface Singer{

   AudioClip Sing(Song s);

}

public interface SongWriter{

   Song compose(boolean hit);

}

在现实生活中,有些歌唱家本身也是作曲家。因为是使用接口而不抽象类来定义这些类型,所以对于一个类而言,它同时实现Singer和Songwriter是完全允许的。实际上还可以定义第三个接口,它同时扩展了Singer和Songwriter,并且加入一些适合于这种组合的新方法:

   public interface SingerSongwriter extends Singer,Songwriter{

       AudioClip strum();

       Void actSensitive();

}

如果要满足这样的一种灵活性,抽象类是不可能完成的。

虽然接口不允许包含方法的实现,但是,使用接口定义类型并不妨碍你为程序员提供实现上的帮助,在本系统的接口设计与实现中借鉴了Java API中的将接口类与抽象类的优点结合起来,将期望导出的每一个重要接口,都提供一个抽象类的骨架实现(skeletal implementation)类。按照惯有编码命名习惯,将该骨架实现类命名为AbstractInterface

在该系统中采用这种方式的来设计的接口有Business(业务)接口,DAO(数据访问对象)接口。

  1. 自定义标签的设计

在对系统的实现中,由于在表现层使用的是基于MVC的Struts框架,该框架中为了在表现层的JSP页面中不混合大量的Java代码,及保持JSP页面的程序的容易读性而提供了相应的Struts自己的一套标签,但是考虑到本系统的实际应用的功能实现。且这些功能实现又是Struts标签没法满足要求的,因此在该系统框架中实现了自己的一套标签,主要有<smart:submit></smart:submit>,<smart:select></smart:select>。

  1. <smart:submit>标签:

设计意图:

在一般的基于B/S结构的web应用系统中,在页面上经常是会涉及到添加、编辑、删除几种常用的功能,在早期的一些开发编码中,相当一部分人是将这几种功能分为多个页面来实现,例如:添加用一个add.jsp页面,编辑用一个edit.jsp页面,删除用一个delete.jsp页面。而这些的页面的代码80%以上都基本上是一样的,只不过是上显示的按钮及在点击相应的提交给后台处理方法不一样。为了达到在一个页面上面实现添加、编辑、删除功能,并且要保持页面代码的清晰可读性,因此,在本系统框架中,封装了自定义的提交标签。

表1 <smart:submit>标签属性列表

属性名称

属性描述

备注

Id

该标签元素的id 。

Name

该标签元素的名称。

Property

当点击该标签所显示的内容后所提交的参数名称

Message

该标签在页面上所显示的值,等同于html标签组里面的input标签的value属性。

displayControl

是否要对该标签的内容是否在页面上显示出来作控制。

只有两种值

true/false

Image

该标签在页面显示的内容的背景图片。

onClick

当点击该标签所展现的内容后所触发的事件。

  1. <smart:select>标签:

设计意图:

在一般的基于B/S结构的web应用系统中,在页面上经常要用到下拉框,且在JSP页面加载出来时就有一组相应的值,为了在加载该页面时动态的、带条件的取其标签相应的键/值对,因此,在本系统框架中,封装了自定义的下拉菜单。

表2 <smart:select>标签属性列表

属性名称

属性描述

备注

name

该标签元素的名称。

property

该标签元素属性名称,与Struts中的html标签的property元素是一样的含义,对应于FormBean里面的一个域。

content

该标签属性为标签取值的业务代码。

multiple

该属性同html标签组中的select标签的multiple属性。

size

该属性同html标签组中的select标签的size属性。

style

该属性同html标签组中的select标签的style属性。

relationValue

该属性为在加载该标签相应的值时的条件。

  1. 基于Struts表现层设计

大部分基于B/S结构的web应用系统中,在页面上经常会出现一个以上的功能按钮,而这些功能按钮基本上都是对应于后台的一个操作实现,由于在本系统中的表现层选用较为成熟Struts框架,该框架中最为核心的部分要属控制器控制转发相应的HttpRequest,其中的LookupDispatchAction类是允许你指定一个具有多个方法的类,每一个方法的调用都基于配置文件中指定的一个特殊请求参数值,利用该参数值反向查询资源绑定,并将它与类中的一个方法进行匹配。从这些功能可以看出Struts是满足对系统页面上多个功能按钮与实现的绑定。

因此,在对本系统进行架构设计的时候,考虑建立一个抽象的BaseAction类,该类继承LookupDispatchAction,实现LookupDispatchAction类中的getKeyMethodMap方法,在方法中返回本系统中请求参数值与资源文件中参数值的键/值对。实现一些对于所有的Action都是有可能用到的公共方法,包括从session中得到用户的信息;对页面上按钮是否显示的控制;检查用户权限;对公共业务逻辑接口的调用等等。在涉及到系统的具体开发实现的时候,要求所有开发人员在写自己的Action的时候统一继承BaseAction。

  1. 基于Hibernate持久层设计

本系统的持久层是基于开源的Hibernate来实现的,在了解到相关的Hibernate特性后,在本系统的框架中,从如下几个方面对其进行了进一步的封装。

  1. 对产生Session实例进行封装

设计意图:

Session是Hibernate持久化操作的基础。注意这里Session的含义,它与传统意义上的Web层的HttpSession并没有什么关系。Hibernate Session之与Hibernate,相当于JDBC Connection与JDBC。

Session作为贯穿Hibernate的持久化管理器核心,提供了众多持久化方法,如save、update、delete,find等。通过这些方法即可透明地完成对象的增删改查(CRUD)。但是值得注意的是,Hibernate Session的设计是非线程安全的,也就是说,一个Session实例同时只可由一个线程使用,同一个Session实例的多线程并发调用将导致难以预知的错误。

因此在本框架中对通过SessionFactory所产生的Session。进行了线程安全性的处理,在实现的HibernateSessionFactory类新建一个Java中的ThreadLocal类,将每次产生Session放入该类中,这样就达到了线程安全性的效果了。

当产生Session而创建SessionFactory实例时,也要注意对SessionFactory重用的问题,因为SessionFactory中保存了对应当前数据库配置的所有映射关系,同时也负责维护当前的二级缓存和Statement Pool。由此可见,SessionFactory的创建过程必然非常复杂、代价高昂,而这也意味,在系统设计中要充分考虑到SessionFactory的重用策略。由于SessionFactory采取了线程安全的设计,可由多个线程并发调用,大多数情况下,一个应用中针对一个数据库共享一个SessionFactory实例即可。

  1. 对通常的数据库操作进行封装

设计意图:

   在系统的设计架构中考虑到代码的重用性,因此对一些通用的数据库的操作都将其封装到一个公共类中,这样就减少了系统开发人员的代码编写工作量,也避免了同功能代码的重复编写。

 

 

 

 

 

 

 

 

  1. 系统总体框架具体实现
  2. 各层具体实现
  3. 表现层

在本系统中的表现层实现了一个抽象的BaseAction类,该类继承LookupDispatchAction,实现LookupDispatchAction类中的getKeyMethodMap方法,在方法中返回本系统中请求参数值与资源文件中参数值的键/值对。实现一些对于所有的Action都是有可能用到的公共方法。部分代码如下所示:

public abstract class BaseAction extends LookupDispatchAction {

//实现父类的方法

       protected Map getKeyMethodMap() {

              Map map = new HashMap();

              map.put("button.save", "save");

              map.put("button.cancel", "cancel");

           …………………..

              return map;

       }

    //统一的业务逻辑调用方法

       protected Object call(Carrier vo) {

        PublicProxy proxy = PublicProxy.getInstance();

        Object obj = null;

        try {

            obj = proxy.process(vo);

        } catch (ApplicationException ex) {

            throw ex;

        }

        return obj;

}

//显示页面按钮

       protected void showButton(String buttonName) {

        Map btnMap = getButtonMap();

        btnMap.put(buttonName, "true");

    }

    //隐藏页面按钮

    protected void hideButton(String buttonName) {

        Map btnMap = getButtonMap();

        btnMap.put(buttonName, "false");

    }

    …………………………………

}

  1. 业务层

在本系统中的业务层实现了一个单例的PublicProxy类,系统中所有的表现层与业务层的交互都要通过这个类来实现。该类结合了Spring框架的相应的API对业务接口与其实现的对应关系的xml文件进行了解析,详见下面的类中的process方法中对xml文件的读取。

public class PublicProxy {

    private static PublicProxy instance = null;

    private static Object lock = new Object();

    private PublicProxy() {

    }

    //返回唯一的实例

    public static PublicProxy getInstance() {

        if (instance == null) {

            synchronized (lock) {

                if (instance == null) {

                    instance = new PublicProxy();

                }

            }

        }

        return instance;

}

//相应的业务处理公共接口

    public Object process(Carrier aop) {

        Business business = null;

        ApplicationContext context

= new ClassPathXmlApplicationContext("beans/*.xml");

        business = (Business) context.getBean(aop.getBusiness());

        return business.process(aop);

    }

}

  1. 持久层

本系统的持久层是基于开源的Hibernate来实现的,结合Hibernate提供的API提供相应实现的部分代码如下所示:

public class HibernateSessionFactory {

    …………………

    private static final ThreadLocal thread = new ThreadLocal();

    //打开一个新的session

    public static Session openSession(boolean useCurrent) {

        Session session = null;

        if (useCurrent && thread.get() != null) {

            session = (Session) thread.get();

        }

        if (session == null) {

            try {

                if (factory == null) {

                    factory = new Configuration().configure(

                            CONFIG_FILE_LOCATION).

                              buildSessionFactory();

                }

                session = factory.openSession();

                 //将session放入ThreadLocal中实现线程安全性设计

                thread.set(session);

            } catch (HibernateException ex) {

                ex.printStackTrace();

            }

        }

        return session;

    }

    ………………

}

  1. 测试与分析
  2. 测试环境

本次测试的环境的硬件环境与系统的开发环境中的硬件环境相一致,只是在软件环境中用了开源的Apache Jmeter,它是一个100%的纯java桌面应用,用于压力测试和性能测量。它最初被设计用于Web应用测试但后来扩展到其他测试领域。

  1. 测试结果

在本次测试中,用Jmeter作了相应的压力测试,其他的测试都是通过手工写程序完成各层的功能测试,在通过对Jmeter的在用户数、循环次数的配置,对本系统框架作的几次压力测试。压力测试部分结果如下:

用Jmeter模拟了1000个用户并发一次请求,循环5次后的结果图如下:

用Jmeter模拟了5000个用户并发一次请求,循环5次后的结果图如下:

 

  1. 结果分析

在对本系统进行的各层的功能测试中,在分层测试的时候,各层程序功能运行正常,对各层功能的衔接测试也达到了很好运行效果,从功能上、性能上都能够满足系统需求分析中的要求。

在对本系统进行的压力测试中,从JMeter测试结果图显示的样本数目、平均、偏离、吞吐量、中值的数值可以看出本系统是满足可伸缩性、可靠性要求的。

结    论

通过本次课题的研究,在结合J2EE领域比较优秀成熟的框架的基础上,对系统进行了分层架构,完成了对基于Struts表现层扩展与开发,加入适合本框架的一些特性。在表现层与业务层之间的衔接上,设计并实现了通过一个公共的代理类来交互,在基于Hibernate的持久层的设计与开发中,实现了对一些常用功能操作的封装。从总体上来说,实现了一个具有实用价值的框架,利用该框架来进行开发的SMART系统具有可扩展性、可维护性等优秀软件所要达到的特点。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/413891.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

英文译中文翻译-中文英文翻译在线翻译

如果您需要在线翻译英文文本为汉字&#xff0c;您可以使用各种在线翻译服务或应用程序。以下是一些您可以尝试的在线翻译服务&#xff1a; Google翻译&#xff1a; Google翻译是一款广受欢迎的在线翻译服务&#xff0c;可将英语文本翻译成汉字。只需将需要翻译的英文文本复制粘…

MFC动态库封装

1.MVC的设计模式的使用 经典MVC模式中&#xff0c;M是指业务模型&#xff0c;V是指用户界面&#xff0c;C则是控制器&#xff0c;使用MVC的目的是将M和V的实现代码分离&#xff0c;从而使同一个程序可以使用不同的表现形式。其中&#xff0c;View的定义比较清晰&#xff0c;就…

自动化面试题4

1、工业中常见的通信方式都有哪些&#xff0c;各自特点是什么&#xff1f; 2、对于一台新的伺服驱动器来说&#xff0c;需要设置哪几个方面的参数&#xff1f; &#xff08;1&#xff09;参数初始化 &#xff08;2&#xff09;点动测试电机旋转方向 &#xff08;3&#xff09;惯…

神经网络/深度学习(二)

Seq2Seq 模型 Encoder-Decoder Attention 机制 Self-Attention 自注意力机制 Transformer 摘文不一定和目录相关&#xff0c;但是取自该链接 1. Seq2Seq 模型详解 https://baijiahao.baidu.com/s?id1650496167914890612&wfrspider&forpc Seq2Seq 是一种循环神经网…

云原生——容器技术docker基础命令

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏云原生专栏 &#x1f4e7;如果文章知识点有错误的地方&#xff0c;请指正&…

d2l语言模型--生成小批量序列

对语言模型的数据集处理做以下汇总与总结 目录 1.k元语法 1.1一元 1.2 二元 1.3 三元 2.随机抽样 2.1各bs之间随机 2.2各bs之间连续 3.封装 1.k元语法 1.1一元 tokens d2l.tokenize(d2l.read_time_machine()) # 因为每个⽂本⾏不⼀定是⼀个句⼦或⼀个段落&#xff0…

认识C++指针

目录 前言&#xff1a; 1.指针未初始化的危险性 2.指针与十六进制数字 3.使用new分配内存空间 4.使用delete释放内存 5.使用new来创建动态数组 6.使用动态数组 7.指针运算 前言&#xff1a; 期待已久的指针篇来啦&#xff0c;这篇全都是有关指针的知识&#xff0c;喜欢…

【Matlab算法】粒子群算法求解二维线性优化问题(附MATLAB代码)

MATLAB求解二维线性优化问题前言正文函数实现可视化结果前言 二维线性优化问题指的是在二维空间中&#xff0c;对于一个由线性函数构成的目标函数&#xff0c;通过限制自变量的范围或满足特定的约束条件&#xff0c;寻找一个最优解&#xff08;最小值或最大值&#xff09;。这…

【精华】表格结构识别模型研究进展

表格结构识别模型研究进展 合合信息&#xff1a;表格识别与内容提炼技术理解及研发趋势 OCR之表格结构识别综述 表格识别技术综述 用于表检测和结构识别的深度学习&#xff1a;综述 &#xff08;1&#xff09;PP-Structure 速度提升11倍&#xff0c;一键PDF转Word PP-St…

MATLAB | 这些各种各样的花里胡哨的折线填充图咋画

这些各种各样的花里胡哨的折线填充图咋画&#xff1f; 折线下面填充纯色的话area函数很容易做到&#xff0c;但上面那些各种花里胡哨的填充图就没那么容易做到了&#xff0c;本期就来讲讲这些玩意都是咋画的&#xff1a; 事先说明&#xff0c;为了绘图好看本文绝大多数图像都使…

Vue3步骤条(Steps)

Vue2步骤条&#xff08;Steps&#xff09; 可自定义设置以下属性&#xff1a; 步骤数组&#xff08;steps&#xff09;&#xff0c;类型&#xff1a;Array<{title?: string, description?: string}>&#xff0c;默认 [] 当前选中的步骤&#xff0c;设置 v-model 后&a…

Java13-多线程

一&#xff1a;基本概念&#xff1a;程序&#xff0c;进程&#xff0c;线程 程序&#xff1a; 是完成特定任务&#xff0c;用某种语言编写的一组指令集合&#xff0c;即指一段静态的代码。 进程&#xff1a;是程序的一次执行过程&#xff0c;或是正在运行的一个程序。 线程&…

Linux系统之MobaXterm远程连接centos的GNOME桌面环境

Linux系统之MobaXterm远程连接centos的GNOME桌面环境一、MobaXterm介绍1.MobaXterm简介2.MobaXterm功能特点二、centos安装GNOME桌面1.本地环境介绍2.安装GNOME桌面环境3.本地进入Linux桌面三、MobaXterm远程连接centos1.打开MobaXterm软件2.远程连接本地Linux系统四、远程连接…

如何利用ChatGPT辅助优化刷题性能

根据土著刷题共建群里的一个小伙伴反馈&#xff0c;刷题会出现切题卡顿的情况&#xff0c;有时会出现滑不动的情况。 定位问题 为了定位切题卡顿问题的具体原因&#xff0c;测试了高低端手机&#x1f4f1;、切换2G、3G、4G低网络状态等各种影响切题的现实情况&#xff0c;经过借…

门店零售系统有哪些功能模块?能带来哪些帮助?

门店零售系统是一种用于管理门店销售、库存、采购等业务的软件系统&#xff0c;可以帮助门店提高管理效率、降低操作风险、优化运营决策&#xff0c;从而增强市场竞争力和顾客满意度。 一、门店零售系统的4大功能 1、商品管理 该模块主要用于管理门店的商品信息&#xff0c;包…

arcgis中地理配准之栅格平移

背景 前面写过一篇文章,是针对有两个对应的栅格数据进行配准的 Arcgis地理配准栅格数据 有时候需要没有对应的栅格数据,只有单幅栅格数据,而且知道平移参数,这时候可以通过平移参数来平移栅格,而且在unity中不能直接识别坐标值很大的数据,只能通过平移将坐标值减少,才…

【分布式事务AT模式 SpringCloud集成Seata框架】分布式事务框架Seata详细讲解

前言 上篇文章我们讲述了如何启动seata的本地服务&#xff0c;并且注册到nacos使用&#xff0c;这篇文章将在SpringCloud中整合Seata框架 上篇文章传送门&#xff1a;https://blog.csdn.net/Syals/article/details/130102851?spm1001.2014.3001.5501 本篇主要内容&#xff…

Docker几个概念

Docker几个概念&#xff0c;有不正确地方欢迎指正 一、首先来看一句话&#xff1a;没有Cgroups就没有LXC&#xff0c;没有LXC就没有Docker。 1、什么是Cgroup呢&#xff1f;Cgroup又名Control group&#xff0c;是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理…

VLAN 基础与划分及配置

我们都知道 VLAN 的中文名为"虚拟局域网"&#xff0c;VLAN 是一种将局域网设备从逻辑上划分成一个个不同的网段&#xff0c;从而实现虚拟工作组的新兴数据交换技术。这一新兴技术主要应用于交换机和路由器中&#xff0c;但主流应用还是在交换机之中。那今天咱们就和海…

Linux网络连接出现问题

报错截图 1.先查看NetworkManager是否启动 systemctl status NetworkManager如果输出结果中包含 "active (running)" 表示 NetworkManager 已经启动并正在运行 2.查看DNS是否配置 cat vim /etc/resolv.conf 1.查看是否有配置信息&#xff0c;如果没有请配置DNS …