《Java EE编程技术》综合应用系统开发_作业管理系统_Struts2_设计报告

目录

一、 需求分析 2

教师: 3

一、教学班导入: 3

二、发布作业: 3

三、教师批阅作业: 3

注意事项: 3

四、 具有统计成绩功能: 4

学生: 4

一、学生查阅所布置的作业,并选择题目完成解答并提交(可以上传附件文件): 4

二、可以查阅教师返回的批阅意见和成绩,若对成绩或评阅有问题,可以返回信息给教师: 4

三、可以列出到目前所作的所有作业情况(包括成绩与评阅信息): 4

二、 结构化分析和面向对象分析 5

三、 结构化设计与面向对象设计 5

四、 具体实现与展示 5

一、数据库设计与实现(数据库字典文档): 5

1. 数据库表目录 6

2. 数据库表结构 6

1、student 6

2、teacher 7

3、publish 发布作业表 7

4、 submit 提交作业表 8

3. 外键关系 9

二、 项目结构设计与实现: 9

1. 部分项目结构图展示: 10

2. 项目具体搭建步骤: 10

2.1. 导入项目必须的jar包: 10

2.2. Web.xml中配置核心控制器(过滤器): 11

2.3. 编写模型类(实体类)entity: 11

2.4. 设计业务控制类(Action类): 12

2.5. 在(src目录下)创建并添加struts2的配置文件struts.xml: 13

2.6. 编写对应的jsp界面: 13

2.7. 最后将项目部署到对应服务器中(例如Tomcat容器)即可运行。 14

3. 项目技术实现(部分举例): 14

3.1. 数据库访问配置: 14

3.2. Action设计与实现: 14

3.2.1. 配置文件实现Action: 15

3.2.2. 注解配置实现Action: 16

3.2.3. 输入验证配置: 17

3.3. 文件上传下载模块(Excel与数据表的转换功能、学生或教师对文档的发布及提交需要依赖次功能): 17

3.4. 采用开源项目preview实现文档的在线预览(以实现老师对作业的在线批改功能(不用一一下载)和实现老师发布文档形式的题目以便同学们查看) 18

4. 实现效果部分展示: 19

首页界面: 19

输入验证失败并返回信息: 20

登录成功实现struts2与前端的传值(EL表达式): 20

进入学生信息管理界面: 20

修改、删除(移除教学班)学生信息等: 21

添加学生信息: 21

注册学生信息: 22

上述学生信息可实现从Excel表到数据库之间的转换等(从Excel表中导入到数据库、从数据表导出到Excel): 22

文档的在线预览功能(老师对作业的在线批改功能(不用一一下载)和实现老师发布文档形式的题目以便同学们查看): 23

还有教师对成绩的批改和意见、学生对问题的疑问和评论界面等。 23

五、 测试用例设计与测试过程 23

凑巧的bug(数据表单null测试用例): 23

六、 其他注意事项 24

一、学会查看tomcat localhost Log 日志文件信息: 24

二、在前端提交表单访问Action时需要注意是jsp标签还是struts2标签(重点注意路径区别): 25

三、注意Action中type类型的取值: 26

 

(这里下面的文档结构由于格式原因,序号标题等产生了一些问题,请见谅)

在拿到老师的项目要求之后,首先确定项目的大体方向,然后根据软件工程的基本思想对该项目进行进一步分析和设计,从而使项目的开发思路更加清晰,项目架构更加合理。

  • 需求分析

合理确定软件的任务与目标,从需求来看,该系统可分为两个模块(教师端与学生端),下面就这两个模块进行进一步需求分析(老师给出的需求报告说明书是基础的需求,在此基础上进行扩充,由于设计需要,一部分设计思路包含在了需求分析中,严格的需求分析是不包含设计和实现思路的):

 

教师:

一、教学班导入:

1.将教学班信息一次导入(Excel格式导入即可),按教学班号进行导入(ExcelToDB执行多条insert语句)。

2.按个人进行导入(输入个人相关信息即可)(单条insert语句)

 

二、发布作业:

每个题目包含:题号、题干(题目内容)、要求、并且给出作业提交的最迟时间等相关内容。

1.数据库记录题目方式:一次可发布多个内容即设置多条insert语句对数据库进行题目补充(根据题目数量执行foreach循环即可)。

2.文件记录题目方式:将多个题目记录在文件中(Word、PDF等格式),学生通过文件预览或者下载的方式获取题目信息(在本地服务器上由于不能引用微软等API服务,不支持在线预览,故在本地服务器下,文件预览时,会将Word等文档转换成图片格式,如果将项目部署到阿里或者腾讯等外网可以访问的服务器地址下则可以引用微软的API服务实现真正的Word预览。)

 

三、教师批阅作业:

1.对每个题目给出评阅意见和成绩,批阅完成后,自动形成该次的评阅成绩和意见。

前端可以采用数据表格格式对每位同学(student_id)的每个答题情况(answer_id)进行打分和给出意见。提交后,后端对表格数据依次插入insert到数据库。

 

注意事项:

由于每位同学的答题有可能重复,因此题目的发布时间(或题目发布的计数编号,因为文件题目的原因首选发布时间)也应作为主键。

有的题目可能是以文件形式发布的,在数据库题目发布统计表中可能不存在,因此如有必要还可以对数据表规定发布属性(简单题目,文件题目)的信息。

 

2.对于上传的附件文档,可以直接打开(不用下载),这样方便教师的批阅。

如有必要,可以将文档分为一栏,批阅作业分为一栏(方便批阅)

(对于学生上传的文档加入必要的信息形成唯一的文件名保存到服务器相应位置上)

 

  • 具有统计成绩功能

教师可以统计到目前为止,学生作业完成情况以及相应的成绩与评价。

select *  from 学生成绩评价表 where ...;

即可完成查询操作,返回到前端列表中。

 

学生:

一、学生查阅所布置的作业,并选择题目完成解答并提交(可以上传附件文件):

1.将学生答题信息放入答题卡表中(应设置是否存在附件(方便老师查看附件信息并打分等,这里对于教师端前端可设置附件按钮,如果有附件则返回附件地址并查看,如果没有则不展示)、批阅状态信息以方便查看是否被批阅),方便老师批阅(批阅后应将成绩等信息insert到成绩审批表)。

2.对于上传的文件附件可必要的信息形成唯一的文件名保存到服务器相应位置上。

二、可以查阅教师返回的批阅意见和成绩,若对成绩或评阅有问题,可以返回信息给教师:

select *  from 学生成绩评价表 where student_id=studentId...;

如果可按作业批次查询则可以:

select *  from 学生成绩评价表 where student_id=studentId and homeworkcount=count...;

返回给列表并空余一列供学生提出意见或问题,update 学生成绩评价表 set 学生疑问=...;这里只允许修改学生意见或问题列,不应修改成绩等信息(也可以单独列一张表记录学生反馈的信息)。

 

三、可以列出到目前所作的所有作业情况(包括成绩与评阅信息):

select *  from 学生提交作业表(发布作业表) where student_id=studentId...;

 

select *  from 学生成绩评价表 where student_id=studentId...;

可将上述两张表结合到一起(注意附件),查看自己的作业情况和成绩评价等情况。

 

  • 结构化分析和面向对象分析
  1. 确定项目中每个模块的功能及行为(必要时采用建模与绘图等方式对项目进行构建)(例如对于本项目教师管理学生教学班子模块的增删查改等功能可采用用例图等方式进行功能和行为的确定)。
  2. 确定数据字典和包图类图等对象的关系和属性(采用UML方式进行构建即可),对于实体类以及属性的确定可在数据库可视化软件Navicat的UML构建下进行构建(也可采用Rose、Visio等进行分析)。
  3. 确定数据的流动方向:由于本次采用struts2框架,因此大致的数据流动方向如下:

数据库DB——>通过JDBC数据库驱动连接或者c3p0数据库连接池——>dao层——>(传递给service服务层)——>Action控制层——>通过EL表达式或者json数据串等格式返回给前端展示。

 

  • 结构化设计与面向对象设计
  1. 设计项目的大体结构(体系结构设计):(由于采用struts2框架方式与MVC的设计思想,因此大体框架结构基本同上述分析阶段的数据流动方向分析的架构)。
  2. 软件接口设计:根据分层次的设计思想,接口的下一层应提供给上一层服务而上一层无需知道下一层的内部实现。同时应设置一些接口来降低耦合,实现项目代码的通用性、可复用性,比如我们常常在dao层设置一些访问和操作数据库的接口并以泛型形式增强代码的通用性与可复用性。
  3. 过程设计:通过流程图等方式展示程序的运行流程(MVC思想)。
  4. 系统设计:将系统逐步细化,分为教师子系统与学生子系统两个大的子系统,然后再根据实际情况进行拆分,例如教师子系统可以分为学生管理子系统(教学班管理子系统),作业发布与成绩审批子系统等等。
  5. 对象设计:根据对象之间的关系和对象的固有属性构建模型(例如UML图等)。
  • 具体实现与展示

一、数据库设计与实现(数据库字典文档):

这里为了实现的简便,简化了数据表数量和数据表单内容(但属性和必要值不缺少,只是在一定程度上简化了关系,重点注意主外键的设计)。

  1. 数据库表目录

序号

表名

注释/说明

1

publish

发布作业表

2

student

 

3

submit

提交作业表(包含提交后教师对学生的打分评价情况以及学生查看成绩后的疑问反馈情况)

4

teacher

 

 

  1. 数据库表结构

1、student 

序号

列名

数据类型

长度

主键

允许空

列说明

1

s_id

int

 

 

学生id(账号)

2

s_password

varchar

20

 

密码(最初与id一致)

3

s_name

varchar

20

 

学生姓名

4

s_college

varchar

30

 

学院

5

s_department

varchar

30

 

系别

6

s_class

int

 

 

教学班号,按int类型进行定义,分为1班、2班等等(此处教学班也应单独设置一张表,然后建立外键对应关系,这里简略处理,不再建表)

7

s_sex

varchar

10

 

性别

8

s_email

varchar

30

 

邮件,这里为了简便,联系方式统一使用邮件

2、teacher 

序号

列名

数据类型

长度

主键

允许空

列说明

1

t_id

int

 

 

教师id(账号)

2

t_password

varchar

20

 

密码(最初与id一致)

3

t_name

varchar

20

 

教师姓名

4

t_college

varchar

30

 

学院

5

t_department

varchar

30

 

系别

6

t_sex

varchar

10

 

性别

7

t_email

varchar

30

 

邮件,这里为了简便,联系方式统一使用邮件

3、publish 发布作业表

序号

列名

数据类型

长度

主键

允许空

列说明

1

id

int

 

 

每次发布时的题号

2

content

varchar

255

 

题目内容

3

requirement

varchar

255

 

题目要求

4

publish_count

int

 

 

该次发布题目的次数(第几次作业)

5

publish_time

datetime

 

 

发布时间

6

deadline

_time

datetime

 

 

截止时间

7

t_id

int

 

 

哪个老师发布的(哪个老师出的题)

  1. submit 提交作业表

(包含提交后教师对学生的打分评价情况以及学生查看成绩后的疑问反馈情况)

序号

列名

数据类型

长度

主键

允许空

列说明

1

id

int

 

 

每次发布时的题号

2

publish_time

datetime

 

 

发布时间

3

t_id

int

 

 

哪个老师发布的(哪个老师出的题)

4

s_id

int

 

 

学生id(账号)(哪个学生做的该题目)

5

answer

varchar

255

 

学生对题目的回答

6

achievement

int

 

 

老师对学生回答情况进行打分(成绩)

7

evaluation

varchar

255

 

老师对学生回答的评价(建议或意见等)

8

feedback

varchar

255

 

学生对教师评价后的反馈信息(学生提交后不允许修改回答等表中其他信息,比如成绩等)

 

  1. 外键关系

外键名

字段

参考模式

参考表

参考字段

删除时

更新时

teacher_id_publish

t_id

homework

teacher

t_id

CASCADE

CASCADE

 

 

 

 

 

 

 

publish_id_submit

publish_time, id, t_id

homework

publish

publish_time, id, t_id

CASCADE

CASCADE

student_id_submit

s_id

homework

student

s_id

CASCADE

CASCADE

teacher_id_submit

t_id

homework

teacher

t_id

CASCADE

CASCADE

 

  • 项目结构设计与实现:

 

  1. 部分项目结构图展示:

 

  1. 项目具体搭建步骤:
    1. 导入项目必须的jar包:

首先将struts2必须的jar包并构建到路径中:

其次将项目中用到的其他jar包构建到项目中(如c3p0数据池管理jar包,commons-fileupload文件上传下载的jar包,jxl实现数据库与Excel互相转换的jar包,mysql数据驱动连接的jar包等等):

 

    1. Web.xml中配置核心控制器(过滤器):

<filter>

        <filter-name>struts2</filter-name>

      <filter-class>      

                org.apache.struts2.dispatcher.ng.filter

         .StrutsPrepareAndExecuteFilter

       </filter-class>

  </filter>

 

  <filter-mapping>

       <filter-name>struts2</filter-name>

       <url-pattern>/*</url-pattern>

  </filter-mapping>

 

    1. 编写模型类(实体类)entity:

注意必须遵守JavaBean规范,必须要有默认构造函数,注意命名规范。

这里记录一个bug:在测试Struts2的Action接收jsp页面时表单数据为null,实际上就是由于命名不规范导致的原因:Struts对变量的get和set方法有严格的要求,以get为例,如果你的变量分别是username,userName,uName,那么对应的get方法就是getUsername(),getUserName(),getUName(),总结起来就是首字母必须大写。Eclipse/IDEA生成get方法一般是符合这一规范的,但是当变量名为uName时,默认生成的时getuName(),而不是正确的 getUName(),这时候就不符合struts2的命名规范了然后非常难发现这个问题,因为越是eclipse/idea等IDE自动生成的代码,我们越相信但实质上已经错了,struts2内部赋值的时候便会找不到该值即null参考:https://blog.csdn.net/Yuwen_forJava/article/details/80178222

当时在测试StudentAction与jsp传值时便一直在报null错误,代码静态结构分析也没有观察出有什么错误,而且在在动态分析下发现初始传值部分即为null而不是数据库或者dao层之间的问题,完全可以确定是发生在StudentAction与jsp页面之间的传值错误。修改student实体类的命名规范后发现传值成功。(细节决定成败,一定注意规范。)(不过这也是struts一点非常不好的地方,格式过于死板。在文件上传下载时命名规范更是有着严格的要求。)

 

    1. 设计业务控制类(Action类):

引入业务模型对象属性(JavaBean)(private),每次通过get方法获取该JavaBean对象的参数值,注意必要属性一定要有get、set函数。否则获取不到无法进行传值。

例如:

//必要字段属性的get、set方法
public StudentEntity getStudentEntity() {
   return studentEntity;
}

public void setStudentEntity(StudentEntity studentEntity) {
   this.studentEntity = studentEntity;
}

public String getRe_password() {
   return re_password;
}

public void setRe_password(String re_password) {
   this.re_password = re_password;
}

public String getMsg() {
   return msg;
}

public void setMsg(String msg) {
   this.msg = msg;
}

    1. 在(src目录下)创建并添加struts2的配置文件struts.xml

action name是调用Action方法的名字,class是对应的Action类,method是对应的execute方法。

再次记录一个bug:

<constant name="struts.action.extension" value="do,action"/>

该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。起初要访问的资源不属于action,跳转就出现404,即被struts2拦截掉了。

因此一定要注意配置文件选合适的,配正确的。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <!-- 启用动态方法调用 -->
    <constant name="struts.enable.DynamicMethodInvocation" value="true" />
    <!--  开发提示:出错时打印更详细的信息-->
    <constant name="struts.devMode" value="false" />
    <!--指定编码集,等价HttpServletRequest.setCharacterEncodint方法-->
    <constant name="struts.i18n.encoding" value="UTF-8" />
    <!--设置浏览器是否缓存静态内容,开发阶段关闭,运行时开启-->
    <constant name="struts.serve.static.browserCache" value="false" />
    <!--当struts.xml配置文件修改后,系统是否重新加载该文件-->
    <constant name="struts.configuration.xml.reload" value="true" />
    <!-- 能够重新加载国际化文件-->
    <constant name="struts.i18n.reload = true" value="true" />

    <!-- 指定请求的后缀是.do或.action,指定多个请求后缀用逗号分隔-->
<!--    <constant name="struts.action.extension" value="do,action"/>-->

    <!-- 添加login的配置信息 -->
    <include file="struts-login.xml"/>

</struts>

 

    1. 编写对应的jsp界面:

例如from数据提交界面,表单中action配置与struts.xml文件中的action name一一对应。同时在from表单中的属性名name要与业务控制层Action中的属性一一对应。(各组件实现数据共享是通过“Action容器”实现的,所以,在提交页面和从Action实现的跳转页面中所共享的数据,必须与Action属性一样。)

 

    1. 最后将项目部署到对应服务器中(例如Tomcat容器)即可运行。

 

  1. 项目技术实现(部分举例):
    1. 数据库访问配置:

①可以采用JDBC方式对数据库进行访问,这里对于JDBC方式不再赘述。

②c3p0数据池方式:

首先进行c3p0的配置(c3p0.properties文件):

注意时区、字符格式等(很容易出现时区问题)

c3p0.user=root
c3p0.password=123456mjg
c3p0.driverClass=com.mysql.cj.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql://localhost:3306/homework?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
c3p0.initPoolSize=5
c3p0.maxPoolSize=10

然后在数据库工具类里引用c3p0数据库连接池:

//该类使用C3P0连接池技术实现数据库连接组件
package db_util;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.*;

public class JdbcPoolUtils {
   private static DataSource dataSource = new ComboPooledDataSource();

   public static Connection getConnection() throws SQLException {
      return dataSource.getConnection();
   }

  ......

}

    1. Action设计与实现:

为了实现技术的练习,分别采用配置文件和注解实现不同的模块,例如在学生模块采用配置文件实现,在教师模块采用注解实现。同时增加了输入验证的内容。

      1. 配置文件实现Action:
public class StudentAction extends ActionSupport {
   private static final long serialVersionUID = 1L;
   //对于studentEntity和re_password需要使用get、set函数
   private StudentEntity studentEntity;
   //用于注册时验证密码是否一致
   private String re_password;
   private String msg;
   private StudentDao studentDao = new StudentDao();

......

}



<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>

    <package name="default" namespace="/login" extends="struts-default">

        <action name="register" class="action.student.StudentAction" method="studentRegister" >
            <result name="success">/login/register_success.jsp</result>
            <result name="error">/login/register.jsp</result>
            <!-- 输入验证失败,重新返回注册界面并展示错误消息 -->
            <result name="input">/login/register.jsp</result>
        </action>

        <action name="login" class="action.student.StudentAction" method="studentLogin">
            <result name="input">/login/login.jsp</result>
            <result name="failure">/login/login.jsp</result>
            <result name="success">/login/login_success.jsp</result>
        </action>

    </package>
</struts>

      1. 注解配置实现Action:
@Namespace("/teacher")
@Scoped(Scope.REQUEST)
@ParentPackage("struts-default")  //表示继承的父包
public class TeacherAction extends ActionSupport {

    private TeacherEntity teacherEntity;  //传入提交值(插入记录)
    private String msg;    //返回运行后的信息
    private TeacherDao teacherDao=new TeacherDao();
    private static final long serialVersionUID = 1L;
    // 老师登录Action方法
    @Action( //表示请求的Action及处理方法
            value="login",
            results={@Result(name="success",location="/login/login_teacher_success.jsp",type="dispatcher"),
                    @Result(name="failure",location="/login/login_teacher.jsp",type="dispatcher")}
    )
    public String teacherLogin() throws Exception {
        String forward = null;
        TeacherEntity teacherEntity2 = teacherDao.find(teacherEntity);
        if (teacherEntity2 != null){
            System.out.println(teacherEntity2.getTId()+teacherEntity2.getTPassword()+"登录");
        }else{
            System.out.println("teacherEntity2 is null");
        }
        if (teacherEntity2 != null&&teacherEntity2.getTPassword().equals(teacherEntity.getTPassword())) {
            forward = "success"; //登录成功标记值
        } else {
            msg="用户不存在 或密码不正确,登录失败,请重新登录或注册!";
            forward = "failure";//登录失败标记值
        }
        return forward;
    }

  ......

}

3.2.3. 输入验证配置:

<validators>
   <!-- 设置输入验证:验证(账号)学号、密码、邮件格式以及密码是否一致等 -->
   <field name="studentEntity.SId">
      <field-validator type="int" short-circuit="true">
         <message>用户账号不能为空!且用户账号格式应为数字型账号!</message>
      </field-validator>
   </field>

   <field name="studentEntity.SName">
      <field-validator type="requiredstring" short-circuit="true">
         <param name="trim">true</param>
         <message>用户名不能为空!</message>
      </field-validator>
      <field-validator type="regex">
         <param name="regexExpression"><![CDATA[^[a-zA-Z]\w*$]]></param>
         <message>用户名格式不正确!</message>
      </field-validator>
   </field>

......

</validators>

    1. 文件上传下载模块(Excel与数据表的转换功能、学生或教师对文档的发布及提交需要依赖次功能):
@Namespace("/student")
@Scoped(Scope.REQUEST)
@ParentPackage("struts-default")  //表示继承的父包
public class UploadStudentAction extends ActionSupport {
   private static final long serialVersionUID = 1L;
    /**
     * 上***个文件方式,必须设置下面的3个属性,File属性名与提交页面的属性名一致,
     * 其他两项必须用该属性名开始并且名称需要注意格式规范
     */
   private File file;//上传文件对象
   private String fileContentType;//上传文件内容类型
   private String fileFileName;//上传文件名

   public File getFile() {
      return file;
   }
   public void setFile(File file) {
      this.file = file;
   }
   public String getFileContentType() {
      return fileContentType;
   }
   public void setFileContentType(String fileContentType) {
      this.fileContentType = fileContentType;
   }
   public String getFileFileName() {
      return fileFileName;
   }
   public void setFileFileName(String fileFileName) {
      this.fileFileName = fileFileName;
   }
   @Action( //表示请求的Action及处理方法
         value="upload",          
         results={@Result(name="success",location="show",type="redirectAction")}
      )  
   public String upload() throws Exception {  
      //获取服务器容器对象
      ServletContext servletContext = ServletActionContext.getServletContext();
      //获取实际存放上传文件的文件夹(项目根目录下的文件夹upload),若不存在,自动创建该文件夹
      String dir = servletContext.getRealPath("/upload");
      System.out.println(dir);      
      File saveFile=new File(dir,fileFileName);
      //FileUtils.copyFile(file,saveFile);实现文件的复制(复制文件到服务器上)
      FileUtils.copyFile(file,saveFile);
      DbToExcel.excelToDb(dir+"/"+fileFileName, "student", "(s_id,s_password,s_name,s_college," +
            "s_department,s_class,s_sex,s_email)", 8);
      return "success";
   }

FileUtils.copyFile(file,saveFile);命令实现文件的复制(复制文件到服务器上)(注意路径)

这里不再赘述。

 

    1. 采用开源项目preview实现文档的在线预览(以实现老师对作业的在线批改功能(不用一一下载)和实现老师发布文档形式的题目以便同学们查看)

需要同时运行两个项目(端口号不一样)以实现本地服务器在线预览等功能。

选用该开源项目原因:

首要原因是本地服务器即可,不需要外网访问的服务器,省略了部署服务器的时间,本地测试效果好(微软office提供的API和XDoc提供的在线预览服务等只支持外部网络可访问到的在线预览服务,不能作为本地测试)(当然如果有阿里或者腾讯云等云服务器微软office提供的API还是非常不错的)。

同时此项目为文件文档在线预览项目解决方案,对标业内付费产品有【永中office】【office365】【idocv】等,在取得公司高层同意后以Apache协议开源出来反哺社区。该项目使用流行的spring boot搭建,易上手和部署,基本支持主流办公文档的在线预览,如doc,docx,Excel,pdf,txt,zip,rar,图片等等。

开源地址:https://gitee.com/wyshp08/file-online-preview

项目运行简略结构图:

 

 

项目引用服务:(运行该开源项目时需要的一系列工作略去):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>预览文件</title>
    <script type="text/javascript">
        var url = 'http://localhost:8080/homework_struts2_war_exploded/resource/JAVAEE编程技术期末综合应用开发.doc'; //要预览文件的访问地址
        window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(url));
    </script>
</head>
<body>
</body>
</html>

  1. 实现效果部分展示:

(由于此次重点在于理解后端架构,因此前端界面美化从简)(不影响功能实现与展示)

 

首页界面:

输入验证失败并返回信息:

登录成功实现struts2与前端的传值(EL表达式):

进入学生信息管理界面:

修改、删除(移除教学班)学生信息等:

 

添加学生信息:

注册学生信息:

上述学生信息可实现从Excel表到数据库之间的转换等(从Excel表中导入到数据库、从数据表导出到Excel):

 

文档的在线预览功能(老师对作业的在线批改功能(不用一一下载)和实现老师发布文档形式的题目以便同学们查看):

这里以老师发布的任务为例:

 

还有教师对成绩的批改和意见、学生对问题的疑问和评论界面等。

 

由于篇幅原因,具体运行界面不再一一赘述。

 

  • 测试用例设计与测试过程

凑巧的bug(数据表单null测试用例):

时间原因,没有太多测试用例,但是也有一部分确实测出了代码问题,比如在实现dao层访问数据库时,findAll()函数内部应该是while(rs.next())结果不小心写成了if(rs.next())(代码复用时出现错误,没有及时改正):

con = JdbcPoolUtils.getConnection();
rs = JdbcPoolUtils.query(con, sql, params);
//一定注意是全列还是单一数据,即采用if(rs.next())还是while(rs.next())
while (rs.next()) {
    student2 = new StudentEntity();
    student2.setSId(rs.getInt("s_id"));
    //密码不展示
    student2.setSPassword(rs.getString("s_password"));
    student2.setSName(rs.getString("s_name"));
    student2.setSCollege(rs.getString("s_college"));
    student2.setSDepartment(rs.getString("s_department"));
    student2.setSClass(rs.getInt("s_class"));
    student2.setSSex(rs.getString("s_sex"));
    student2.setSEmail(rs.getString("s_email"));
    studentlist.add(student2);
}
JdbcPoolUtils.close(rs, null, con);

而此时数据库中数据正好第一条所需数据为null,在这里尽管不会出现null错误,但是却不能展示合理的表单数据,因此修改bug(静态结构分析法,程序插装技术(打印输出)等)又浪费了不少时间。

因此我们在复用代码时一定要仔细检查逻辑的正确性,注意细节问题。

 

  • 其他注意事项

一、学会查看tomcat localhost Log 日志文件信息:

二、在前端提交表单访问Action时需要注意是jsp标签还是struts2标签(重点注意路径区别):

jsp标签:

<%

String path = request.getContextPath();

String basePath = request.getScheme() + "://"

+ request.getServerName() + ":" + request.getServerPort()

+ path + "/";

%>

<a href="<%=basePath%>student/findupdate?SId=${studentEntity.SId}">修改</a>

struts2标签:

(不用添加基础路径,直接访问相应的

<%@ taglib prefix="s" uri="/struts-tags"%>

<s:form action="/student/insert" method="post">

 

注意jsp(HTML)标签与struts2标签属性值的区别:

jsp(HTML)标签:

<tr>

<td align="right">账户名:</td>

<td><input type="text" name="studentEntity.SId" value="${studentEntity.SId}" ></td>

</tr>

<tr>

<td align="right">真实姓名:</td>

<td><input type="text" name="studentEntity.SName" value="${studentEntity.SName}"></td>

</tr>

 

struts2标签:

<s:iterator var="studentEntity" value="studentList" status="list">

            <tr>

                <td><input type="checkbox" name="checkList" value="${studentEntity.SId}"></td>

                <td><s:property value="#studentEntity.SId" /></td>

                <td><s:property value="#studentEntity.SName" /></td>

                <td><s:property value="#studentEntity.SCollege" /></td>

                <td><s:property value="#studentEntity.SDepartment" /></td>

                <td><s:property value="#studentEntity.SClass" /></td>

                <td><s:property value="#studentEntity.SSex" /></td>

                <td><s:property value="#studentEntity.SEmail" /></td>

                <td><a href="<%=basePath%>student/findupdate?SId=${studentEntity.SId}">修改</a>

                    <a href="javascript:deleteconfirm('${studentEntity.SId}')">删除</a></td>

            </tr>

</s:iterator>

 

三、注意Action中type类型的取值:

尤其注意type="dispatcher"与type="redirect"、type="redirectAction"的区别:

type="dispatcher"为默认类型,表示转发,上一个界面中的信息不会丢失,可以被获取,而type="redirect"、type="redirectAction"表示重定向到URL或者Action,上一个界面的信息将会丢失。

 

易产生问题:在EL表达式需要获取值时应采用type="dispatcher",而不是type="redirect"。

 

type的一些其他取值:

stream:向浏览器发送 InputStream 对象,通常用于处理文件下载(比如在导出Excel数据时),还可用于 Ajax 数据。

当然还有chain,用于处理Action链,被跳转的Action中仍能获取上个页面的值如request信息等等。