system: [SYSTEM]

user: 3. 移动教务查询系统开发——以HTTP成绩查询为例 以我校正方教务系统的HTTP 成绩查询为例，讲述基于HTTP 分析模拟技术的Java 开发过程，重点 给出HTTP 学生成绩查询实现过程中的关键设计思想。移动端网络框架Java OKhttp [ 8 ]是一个适于处理 HTTP 交互操作的轻量级网络请求框架，它为实现移动教务查询系统提供了技术基础。不失一般性，其 他类型的教务系统如青果教务系统等[ 9 ]的设计及实现原理基本相同。 3.1. HTTP模拟登录开发 移动教务查询系统首先需要验证学生身份，包含一个HTTP模拟登录模块。通过对用户登录的HTTP交互报文分析，发现浏览器向中央认证服务器以POST的方式发送了一个HTTP请求。教务查询系统HTTP请求消息体中的HTML表单传递了username、password和service三个关键参数，其中，username代表用户的账号名，即在校学生的教务系统账号；password代表该账号的密码；service是一个固定的网址，表示登录到教务系统的管理页面。假若用户名及密码验证成功，认证服务器会返回一个含有JavaScript脚本的页面，它重定向到带有ticket属性的网址。由于HTTP模拟登录技术采用的移动端Java OKhttp网络框架不会自动执行JavaScript脚本，因此需要对JavaScript脚本进行内容分析以确定重定向网址，之后模拟执行URL跳转。首先，通过Java Jsoup组件获取此页面中JavaScript的网络地址URL，然后通过HTML GET方法访问URL网址，从而实现模拟重定向页面跳转。假若用户名及密码验证失败，则返回登录失败页面，此时可在用户界面上提示用户名密码错。 模拟重定向访问JavaScript所含URL网址后，教务服务器会返回一个状态码为302 (重定向)的HTTP响应报文，二次重定向地址正是该报文的HTML a标签中的URL地址。由于该二次重定向行为不是JavaScript脚本执行的，所以需要根据Java OKhttp网络框架的重定向自动与否属性设置来判断是否需要通过HTML GET访问该HTTP响应报文中a标签所含有的URL网址。二次重定向后，返回一个含有JavaScript脚本的HTML页面，分析该JavaScript脚本的含义，发现其将打开一个路径为/xs_main.aspx?xh=(/学号)的HTML页面。因此，在OKhttp网络框架中使用GET方法打开该URL网址，第三次URL重定向而进入教务系统个人主页，完成HTTP模拟登录。假若返回的HTML页面head标题为“正方教务管理系统”，且可以在id为xhxm的span 标签中发现学生的姓名，则表明移动端HTTP模拟登录成功。登录进入个人主页后，可缓存用户个人信息到个人Session对象中，以便跨功能模块使用，整个流程如图1所示。 图1. HTTP 模拟登录流程图化 3.2. HTTP成绩查询开发 查询学期课程成绩是学生最常用的教务功能之一。HTTP成绩查询的前置条件是已登录。当移动端完成HTTP模拟登录后，在Session对象中保存着用户名、密码等个人信息，可直接获取Session对象中的个人信息进行查询。假若用户未登录，Java拦截器会拦截查询请求，并强制跳转到登录界面，要求用户执行HTTP登录。通过分析成绩查询的HTTP交互信息，发现浏览器向服务器以POST方式发出了一个HTTP请求，传递了ddlXN、ddlXQ、Button1、_VIEWSTATE四个HTML关键表单参数。此外，还以GET查询串方式向服务器提交了xh、xm和gnmkdm三个HTML关键参数。 HTML表单参数ddlXN和ddlXQ分别表示成绩查询的学年和学期。HTML表单参数Button1属于固定值，用于服务器标识查询的内容。_VIEWSTATE表单参数是ASP.NET的视图状态值，用于保存会话的Base64编码值，在HTML报文中是一个隐藏域表单数据，表示HTTP交互过程中需要向Web服务器中传递的_VIEWSTATE参数。GET查询串参数xh和xm分别表示学号和姓名，对于中文姓名，通过网络传递UTF-8类型的中文字符，会导致乱码。因此，HTML使用URLEncoder将xm参数进行URL编码，转换为application/x-www-form-urlencoded MIME字符串来传递。GET查询串参数gnmkdm作用同Button1。 在教务系统返回的HTTP响应报文中，查找class属性为datelist的table标签，含有对应学期、学年的成绩信息。每个tr标签包含一个课程成绩信息，每个td标签包含一个基本单元课程成绩信息。利用Java Jsoup可解析和定位目标成绩数据。首先使用Jsoup select选择器查找_VIEWSTATE参数值，然后向教务系统以POST方式提交查询表单，发出HTTP成绩查询请求。最后，系统返回成绩表响应报文，通过Jsoup定位HTML成绩表格，获取表格所有tr元素，循环遍历每个tr元素，可得课程成绩数据表。 RESTful API 是一个API 设计规范，适于HTTP 成绩查询这类轻量级的前后端数据接口设计，Java 技术实现RESTful 接口有三种方法：HttpClient 实现、HttpURLConnection 实现、SpringRestTemplate 实现 [ 10 ]。文中采用简洁的HttpClient 实现RESTful API 以完成移动客户端与Java 控制器端的代理数据交换。 为提高查询性能，考虑将查询获取的成绩数据缓存到高速NoSQL [ 11 ]数据库中，当MongoDB 数据库有 该学生成绩缓存时则直接高速取出使用，当成绩数据不在MongoDB 数据库中时则通过Web 教务服务器 取出学生成绩数据并缓存到MongoDB 数据库。选择MongoDB 这种基于分布式存储的高速NoSQL 数据 库来储存成绩数据，主要考虑是：1) 学生批量查阅成绩往往集中在学期末放假前，易产生成绩查询的高 并发瞬时峰值，MongoDB 数据库可支持大规模数据存储并较好支持高并发低延时的Web 查询，提高用 户响应度和用户查询体验；2) 成绩记录一旦产生，通常没有二次修改，适于成绩查询缓存；3) 高校教务 查询系统应用的复杂度不高，对数据完整性约束要求不强，适用于MongoDB 这种新型的、快速的NoSQL 数据库系统。 3.3. HTTP成绩查询测试 HTTP 成绩查询的前置条件是用户已登录，当Java 拦截控制器检测发现Session 对象未含有用户登录 信息，则拦截查询请求之后强行跳转至登录页面，要求移动客户执行HTTP 登录。当移动端已完成HTTP 模拟登录，Java 控制器可直接提取保存于Session 对象中的用户信息进行成绩查询。由于成绩查询RESTful API 返回的学生成绩数据格式，不是纯文本而是一个Json 通用数据交换格式[ 12 ]，因此，Web 服务器响 应的HTTP 消息头的Content-Type 属性设置为application/json。使用PostMan HTTP 测试器工具测试成绩 查询API 接口，返回的一个JSON 格式的成绩数据示例如 图2 所示，成绩列表GradeList 属性中存放着多 个Grade 信息元素：学年、学期、课程名、学分、课程类型、成绩等。 通过Android SDK API或微信小程序API等移动开发技术提供对移动端开发支持，将返回的Json格式成绩列表GradeList以简洁便利的方式展示在移动终端如手机等，查询效果如图2所示。 图1. 学生成绩查询示例