ClockingIn安卓NFC考勤系统总结(1)

最近完成了本学期的期末设计,在这里做一些总结。

首先说项目结构,项目采用服务端+客户端的模式。
采用spring boot + MySql + Mybaties 配合java实现了带有GUI的服务端。客户端由原生Android开发实现,读卡以及卡片使用Android NFC的读写卡模式和ISO14443类型的13.56Mhz的RFID卡片,经过测试校园卡和水卡都是可以的。一下是在开发过程中碰到了一些问题以及总结。

server端

使用gradle构建

首先该项目使用gradle构建,由于习惯了Android的gradle构建项目,所以在IDEA里面也同样使用了gradle构建而没有选择maven。
首先将远程仓库地址换成国内镜像,比如阿里云。
image.png

结合java GUI

我这里手动改造了spring boot的启动项目,将javax图形界面与application进行了绑定。
image.png
这样在main方法里面先实体化图形界面类MainFrame,该类是一个java控制串口读写的GUI界面,是上一学期的一个实验详情),在github上面也做过总结可以参考。这样一来就可以在接口也就是controller层去控制界面了。比如想要将发送来server的一条语句追加到GUI中的文本显示区域里面就可以这样写。

1
2
3
4
5
6
7
8
9
10
11
/**
* 公用方法:调用函数向服务端发送一天数据,并且添加到文本框中(追加形式)
* @param msg
* @return
*/
@RequestMapping("/setText")
public String appenfText(String msg){
BaseApplication.mainFrame.addMsgNextLine(msg);
System.out.println(msg);
return "发送成功";
}

通过获取主活动类然后近一步调用了图形界面类中的addMsgNextLine()方法向文本区域添加一条语句。该方法为如下

1
2
3
4
5
6
7
/**
* 公用方法向server端窗口添加一行数据
* @param s
*/
public void addMsgNextLine(String s){
mDataView.append(s+ "\r\n");
}

###添加Mybaties以及简单操作

1
compile("org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.0")

配置数据库需要设置端口号,填写MySql数据库用户名和密码,配置数据库url等。Mybaties主要使用方法
这里采用了简便的方法,一方面数据量不是特别大还用重点还是在Android端,所以server端就省略了很多操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
**
* ClockingIn 学生接口
*/
public interface StudentMappper {

/**
* 通过学生名字查询一个学生所有信息
* @param name
* @return
*/
@Select("select * from student where Sname = #{name}")
StudentModel findStuByName(String name);

/**
* 通过教师名字查询该教师的所有课程
* @param teacherName
*/
@Select("SELECT Tclass FROM teacher WHERE Tname= #{teacherName}")
List<Map<String,Object>> findClassByTeacherName(String teacherName);


/**
* 查询选了某课程下的所有学生列表
* @param className
* @return
*/
@Select("SELECT Sname FROM student where Sid = any(SELECT Sid FROM class WHERE Tid = any(SELECT Tid from teacher where Tclass = #{className}));")
List<Map<String,Object>> findStuByClass(String className);

/**
* 通过卡片id查询学生信息
* @param cardNum
* @return
*/
@Select("select Sname from student WHERE Scardnum= #{cardNum}")
String findStuByCardNum(String cardNum);


/**
* 根据学生名字与当前周数更新上课状态
* @param name
* @return
*/
@Update("UPDATE student SET Sone = '上过' WHERE Sname= #{name}")
int updateWeekOneByName(String name);
}

上面Mapper类中,sql语句直接写入了注解后面的括号中,严格来讲需要写入xml文件中。若是字符串参数需要使用#{参数名},这样在编译时候会为传来的参数添加上引号,若是不需要引号只需要原数据,比如需要传入表名或者需要保留原来值。则使用${参数名}的方法来传入参数。
若是查询的多行数据使用了一个List来保存,使用Map来保存查询到的属性名与数据。查询到的学生数据使用下面实体类StudentModel来保存。覆盖toString方法封装为类json形式的数据。选用什么形式在于需要返回什么样的数据格式。更新数据库需要返回int形式的结果(影响的行数)。
学生实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 学生model
*/
public class StudentModel {
String sName;
String sClass;
String sPhone;
String sNumber;
String sCardNum;
int sId;

@Override
public String toString() {
return "StudentModel{" +
"student='" + sName + '\'' +
", class='" + sClass + '\'' +
", phone='" + sPhone + '\'' +
", number='" + sNumber + '\'' +
", cardNum='" + sCardNum + '\'' +
", id='" + sId + '\'' +
'}';
}
}

MySql数据库

数据库操作软件使用的是Navicat,手动建表并且使用了Excel表格导入数据。该方面需要总结的不多,主要用来顺便复习数据库知识了。
若是一个查询之中嵌套了多层子查询,但每个子查询返回的数据都是不唯一的,而且所有查询的数据都需要。这样需要在子查询前使用any关键字,具体如下:

1
2
3
SELECT Sname FROM student where Sid = 
any(SELECT Sid FROM class WHERE Tid =
any(SELECT Tid from teacher where Tclass = #{className}));

Android端

前面的博客中总结过Android 9 网络访问禁止了明文http请求。所以要不给spring boot上ssl,可以使用java工具生成,要不在Android自己配置网络安全文件。这是在换手机时候才发现的问题,所以以后要多关注Android新版本以及change log。Android开发还是需要紧跟着Google脚步走。另外就是熟练了Recyclerview和adapter的使用,广播的发送与接收,跨界面更新ui以及传递信息,其他就是使用了Android原生网络请求,AsyncTask的使用,Android原生json解析处理,还有就是界面方面的一些自主设计,NavigationView+ViewPager+Fragment的常规操作等等,这些对我来说算是Android基础的巩固和复习了,只不过代码略显难看需要重构一些代码来整理一下。

###Android NFC
有关nfc的会在下一篇来总结