简介:外聘教师管理系统是一套基于C#与SQL Server的完整教学/课程设计项目源码,覆盖教师信息维护、多条件查询、工资计算、学校信息维护及系统权限管理等核心模块。系统角色分明,管理员可完整增删改查,普通用户仅可浏览查询,适合用于数据库课程设计或毕业设计参考。压缩包含97个文件,主体为26个C#窗体源码文件与25个界面预览截图,辅以资源文件、配置文件、EXE可执行程序等;数据库部分包含SQL2012的MDF/LDF文件,内置系统数据库,修改连接字符串即可运行。资源包大小约35.47MB,已有437人学习下载。通过该包可获取完整可编译的解决方案(.sln)、分模块的窗体与业务逻辑代码,以及登录、改密、工资核算等功能的界面实现与数据库脚本,便于按图索骥快速改造成自有项目。
1. 外聘教师管理系统:C# + SQL 这条路上,少见的完整闭环案例
某高校教务科每天要处理几十位外聘教师的管理,合同、课时和费用记录都躺在Excel里。我拿到这份《外聘教师管理系统》资源后,第一反应是终于有人把这条业务线做成完整闭环了。它用C# + SQL Server实现教师档案、课程安排、课时费结算、合同到期提醒和用户登录五个模块,数据全部落在数据库里。这套系统不是玩具:适合刚学完C#基础、想找一个完整项目练手的初学者,也适合需要把Excel台账升级为正式系统的开发者。前者看链路怎么走通,后者看数据库怎么拆、分层怎么写。
2. 项目结构拆解:从rar压缩包到能编译的解决方案
2.1 压缩包里通常装着四样东西
rar解压后,我一般先去根目录看README或“使用说明.txt”。这类外聘教师管理系统的打包方式比较统一,里面通常有四个组成部分。第一个是源码目录,里面是以.sln打开的Visual Studio解决方案,对应UI、BLL、DAL、Model四个工程;第二个是数据库脚本,一般是.sql文件,也可能是可以直接附加的.mdf数据库文件;第三个是文档,包括需求说明书、设计文档、使用手册;第四个是Debug目录,里面是编译好的exe和配置文件,用来快速看效果而不是调试代码。
这里的关键点是:当你想跑起来而不是看代码时,直接从数据库脚本建库,再把源码编译一次,基本就能工作。我见过很多人在这一步卡住,是因为没注意到压缩包里还有一份使用说明,里面写清楚了App.config要改哪一行。如果压缩包里没有说明,你就去源码里找App.config。
补充说明:如果rar里只有源代码,没有数据库脚本,那就要到项目中寻找Database文件夹,或者打开DAL层代码看连接字符串里Initial Catalog是什么库名。常见做法是连接字符串指向一个叫TeacherDB的数据库,脚本文件就叫TeacherDB.sql。
2.2 解决方案分层:UI、BLL、DAL、Model
这个项目的解决方案一般按三层架构组织。Model放实体类,比如TeacherInfo、TeachSchedule;DAL放数据访问代码,负责把SQL语句发给SQL Server;BLL放业务逻辑,比如课时费怎么算、合同到期提醒的条件判断;UI层是WinForms窗体,负责把数据展示在DataGridView上。
我一般会先看DAL层,因为它是整个系统的数据出口。DAL里通常会有一个SqlHelper.cs,封装了ExecuteDataTable、ExecuteNonQuery、ExecuteScalar三个基础方法,后续所有业务查询都复用这三个方法。这种写法在C# + SQL的桌面项目里非常常见,好处是SQL语句集中管理,后期改库结构时只需要动DAL层。
再往下看目录结构,可以用表来列:
| 目录名 | 职责 | 关键文件 |
|---|---|---|
| Model | 实体类,对应数据库表结构 | TeacherInfo.cs、TeachSchedule.cs |
| DAL | 数据访问层,执行SQL或调用存储过程 | SqlHelper.cs、TeacherDAL.cs |
| BLL | 业务规则,调用DAL并做判断 | TeacherBLL.cs、SalaryBLL.cs |
| UI | 窗体界面,绑定控件显示 | FormLogin.cs、FormMain.cs |
| Database | 建库脚本和初始化数据 | TeacherDB.sql |
这个结构的优点是新人能一眼看懂数据流:窗体把参数传给BLL,BLL校验后传给DAL,DAL把SQL发给数据库,结果再一层层返回。缺点也明显:当业务变多变复杂后,BLL层容易越来越重,这是后面做二次开发要重点注意的地方。
2.3 第一步要改的配置文件:App.config
sln打开后,如果直接按F5,大概率弹出一个数据库连接相关异常。原因是App.config里的连接字符串写的是作者电脑上的SQL Server实例。我一般会先看UI层项目下的App.config,找到connectionStrings节点。
下面是一份典型的配置:
<connectionStrings> <add name="TeacherDB" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=TeacherDB;Persist Security Info=True;User ID=sa;Password=123456;" providerName="System.Data.SqlClient" /> </connectionStrings>逻辑说明:connectionStrings节点是.NET框架读取连接字符串的标准位置,代码里通过ConfigurationManager.ConnectionStrings["TeacherDB"]就能拿到整段连接串。Data Source指定服务器实例,Initial Catalog指定数据库名,User ID和Password是登录账号。
参数说明:Data Source=.\SQLEXPRESS表示本机的SQL Express实例;如果你装的是SQL Server 2012以上开发版,实例名可能是localdb或本机主机名,需要改成对应的名字。如果数据库是Windows身份验证,可以把Persist Security Info后面部分去掉,改成Integrated Security=True。改完配置别急着编译,先到Visual Studio的服务器资源管理器里测试连接,这一步能过滤掉八成问题。
确认配置文件没问题后,按两次Ctrl+Shift+B编译。如果引用的DLL报黄色感叹号,先右键解决方案还原NuGet包;如果没有NuGet还原,就去每个项目的引用里手动移除失效引用,再重新添加。这个项目不依赖第三方UI库,理论上只要.NET Framework版本匹配就能编译过。如果目标框架是4.6,而你机器上是4.8,不会自动向上兼容,需要在项目属性里把目标框架改为4.8或3.5。
提示:连接字符串里的库名写错时,界面上所有查询都会返回“对象名无效”的SQL异常。数据库名和脚本文件名保持一致最省事。
3. 核心模块拆解:教师从录入到课时费结算的完整链路
3.1 SqlHelper:所有数据库操作都从这一处出门
先从DAL层最底层的SqlHelper开始。这套系统里所有DAL类都依赖它,它其实就做了三件事:拿到连接字符串、执行SQL、把结果返回。下面把三个核心方法精简一下:
public class SqlHelper { private static readonly string connStr = ConfigurationManager.ConnectionStrings["TeacherDB"].ConnectionString; public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters) { using (SqlConnection conn = new SqlConnection(connStr)) using (SqlCommand cmd = new SqlCommand(sql, conn)) { if (parameters != null) cmd.Parameters.AddRange(parameters); SqlDataAdapter adapter = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); adapter.Fill(dt); return dt; } } public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn = new SqlConnection(connStr)) using (SqlCommand cmd = new SqlCommand(sql, conn)) { if (parameters != null) cmd.Parameters.AddRange(parameters); conn.Open(); return cmd.ExecuteNonQuery(); } } }逻辑说明:ExecuteDataTable负责查询,内部用SqlDataAdapter把查询结果填充到DataTable,DataGridView直接绑定这个返回值就能显示。ExecuteNonQuery负责增删改,返回影响行数,大于0说明操作成功。两个方法都接收可变长度的SqlParameter数组,这样就保证上层传参数时不用手拼字符串,降低注入风险。
参数说明:sql是要执行的SQL文本或存储过程名;parameters是SqlParameter数组,调用时写new SqlParameter("@name", value)即可。注意如果SQL里用了@参数,必须在参数数组里声明同名参数,否则会抛“必须声明标量变量”的异常。
3.2 教师档案查询:参数化查询不拼接字符串
接下来看最常用的TeacherDAL.SearchTeacher方法。查询条件通常有三个:按姓名、按手机号、按状态。为了不踩SQL注入的坑,这里用参数化查询:
public DataTable SearchTeacher(string keyword, int status) { string sql = @"SELECT TeacherID, TeacherName, Phone, Title, HourlyFee, Status FROM TeacherInfo WHERE (TeacherName LIKE @keyword OR Phone LIKE @keyword) AND Status = @status"; SqlParameter[] parameters = { new SqlParameter("@keyword", SqlDbType.NVarChar) { Value = "%" + keyword + "%" }, new SqlParameter("@status", SqlDbType.Int) { Value = status } }; return SqlHelper.ExecuteDataTable(sql, parameters); }逻辑说明:这里没有用字符串拼接,而是把keyword和status作为参数传给SQL。LIKE条件里的%和keyword拼在C#端,好处是用户输入单引号时不会把SQL语句破坏掉。UI层调用这段代码时,一般是在窗体的txtSearch.Text输入关键词、comboBoxStatus选状态,然后调用BLL层的同名方法,BLL层再转发给这个DAL方法。
参数说明:@keyword的数据库类型是NVarChar,配合前端传入的字符串;@status是Int。要注意LIKE里面的百分号是写在参数里的,如果写在SQL文本拼接处,还是会有注入风险。这个写法在C# + SQL的桌面系统里几乎是标准答案,比用string.Format拼SQL安全得多。
3.3 课时费结算:存储过程计算和C#端计算怎么选
外聘教师管理系统的核心业务是课时费结算。常见做法是写一个存储过程,让SQL Server算完金额再返回,UI层只负责展示。这是性能考虑,也方便维护:
CREATE PROCEDURE [dbo].[Proc_CalculateTeacherSalary] @TeacherID INT, @PeriodYear INT, @PeriodMonth INT AS BEGIN SELECT T.TeacherID, T.TeacherName, ISNULL(SUM(S.HourCount * T.HourlyFee), 0) AS TotalAmount FROM TeacherInfo T LEFT JOIN TeachSchedule S ON T.TeacherID = S.TeacherID WHERE T.TeacherID = @TeacherID AND S.ScheduleYear = @PeriodYear AND S.ScheduleMonth = @PeriodMonth GROUP BY T.TeacherID, T.TeacherName, T.HourlyFee END逻辑说明:存储过程输入三个参数:教师ID、结算年份、结算月份。它把TeachSchedule里属于这个教师当月的所有课时,乘以TeacherInfo里的HourlyFee单价,求和得到月结费用。LEFT JOIN保证即使这个月这个教师没有课程,也依然返回一行教师的资料,金额显示为0,而不是直接查不到。
调用方式说明:C#端调用存储过程和调用普通SQL没有本质区别。把cmd.CommandType设为StoredProcedure,再传参数:
SqlParameter[] parameters = { new SqlParameter("@TeacherID", SqlDbType.Int) { Value = teacherId }, new SqlParameter("@PeriodYear", SqlDbType.Int) { Value = year }, new SqlParameter("@PeriodMonth", SqlDbType.Int) { Value = month } }; DataTable dt = SqlHelper.ExecuteDataTable( "Proc_CalculateTeacherSalary", parameters);参数说明:这段代码里三个SqlParameter分别对应存储过程的三个入参,类型都用Int。这里有一个容易被忽略的细节:SqlHelper里的ExecuteDataTable方法默认只执行传入的SQL字符串,并不会自动把字符串当成存储过程。所以我在实际项目中会加一层重载,内部判断sql参数是否以“Proc_”开头,如果是就自动设置CommandType。否则必须显式设置cmd.CommandType = CommandType.StoredProcedure,不然SQL Server会把存储过程名当成普通文本SQL去解析,直接报“找不到存储过程”。
3.4 合同到期提醒:Timer控件加一条条件查询就能做
合同到期提醒这个模块完全可以用一个Windows Forms Timer实现。窗体加载后,启动一个定时器,每次触发时查一次数据库,把未来30天内到期的教师查出来:
private void timer1_Tick(object sender, EventArgs e) { SqlParameter p = new SqlParameter("@days", 30); DataTable dt = SqlHelper.ExecuteDataTable( @"SELECT TeacherName, ContractEndDate FROM TeacherInfo WHERE ContractEndDate BETWEEN GETDATE() AND DATEADD(DAY, @days, GETDATE())", p); if (dt.Rows.Count > 0) { // 这里可以更新界面上的DataGridView,或者弹出一次提示 } }逻辑说明:BETWEEN GETDATE() AND DATEADD(DAY, @days, GETDATE())这个写法,含义是“从今天到30天之后”。GETDATE()是SQL Server当前时间,DATEADD在日期上增加指定天数。这里参数@days是30,如果想要60天,直接改成60即可,不用动SQL。
参数说明:注意Timer的时间间隔不宜太短,否则每秒钟都查一次数据库。我一般设置interval为60000,也就是每分钟查一次,桌面系统完全够用。真正上线的话,这种提醒逻辑更适合放到后台服务里,桌面程序做提醒只是一个轻量方案。
到这里,外聘教师管理系统的主链路已经串起来了:登录窗体校验UserInfo表,主窗体分几个Tab,一个管理教师档案,一个管理授课和结算;档案从SqlHelper到TeacherDAL再到TeacherBLL,最后绑定到DataGridView;结算时调用Proc_CalculateTeacherSalary存储过程,把金额展示在列表里。这个链路覆盖了一个典型桌面业务系统从界面到数据库的完整过程,也是这份资源最值得啃的部分。
4. SQL数据库设计:外聘教师这条业务线如何落表
4.1 核心表:教师、授课、结算、用户
打开数据库脚本,前十几行通常是建库语句,后面就是建表。外聘教师管理系统的表不会太多,核心就是四张:TeacherInfo、TeachSchedule、SalaryRecord、UserInfo。先看教师表:
CREATE TABLE TeacherInfo ( TeacherID INT IDENTITY(1,1) PRIMARY KEY, TeacherName NVARCHAR(50) NOT NULL, Gender NCHAR(1) DEFAULT N'男', Phone NVARCHAR(20) NULL, Title NVARCHAR(20) NULL, HourlyFee DECIMAL(10,2) NOT NULL DEFAULT 0, ContractEndDate DATE NULL, Status TINYINT NOT NULL DEFAULT 1 );逻辑说明:TeacherID使用IDENTITY自增,作为主键。HourlyFee是课时单价,这里的单位是“元/小时”,DECIMAL(10,2)可以存最多十万级别的金额,外聘教师课时费一般够用。ContractEndDate是合同到期日期,给合同提醒模块用。Status字段用来做逻辑删除,0表示停用,1表示在职,这样不会物理删掉教师的历史记录。
参数说明:DEFAULT N'男'里的N前缀表示Unicode字符串,避免中文乱码;TINYINT占用1字节,存0/1状态足够。这是一张典型的字典表加业务表合并的写法,简单SQL项目里经常这么干。
再看授课表和结算表:
CREATE TABLE TeachSchedule ( ScheduleID INT IDENTITY(1,1) PRIMARY KEY, TeacherID INT NOT NULL, CourseName NVARCHAR(50) NOT NULL, ClassDate DATE NULL, HourCount DECIMAL(5,1) NOT NULL, ScheduleYear INT NOT NULL, ScheduleMonth INT NOT NULL ); CREATE TABLE SalaryRecord ( SalaryID INT IDENTITY(1,1) PRIMARY KEY, TeacherID INT NOT NULL, SettleYear INT NOT NULL, SettleMonth INT NOT NULL, TotalAmount DECIMAL(10,2) NOT NULL, SettleTime DATETIME NOT NULL DEFAULT GETDATE() );逻辑说明:授课表里拆出了ScheduleYear和ScheduleMonth两个冗余字段,这个设计在报表统计时非常有用,否则每次都要用MONTH(ClassDate)去做函数计算,查询效率会差一些。SalaryRecord的作用是保存每次结算结果,形成历史记录,后面查工资报表不需要重新算,直接查这张表即可。
参数说明:两张表都只用TeacherID关联,没有建立外键约束。这个在真实项目中是有争议的:有的人习惯在建表时加上FOREIGN KEY REFERENCES TeacherInfo(TeacherID),保证数据完整性;有的人故意不加,因为外键会影响批量导入和删除。C# + SQL这类中小项目里两种做法都常见。如果你是初学者,建议加上外键,后面写代码时少很多脏数据问题。
4.2 视图:把月度汇总查询固定成一张虚表
结算存储过程写完后,报表查询经常需要按教师汇总每个月的课酬。与其在C#里拼接SQL,不如直接用视图:
CREATE VIEW v_TeacherMonthSalary AS SELECT T.TeacherID, T.TeacherName, S.ScheduleYear, S.ScheduleMonth, ISNULL(SUM(S.HourCount * T.HourlyFee), 0) AS MonthAmount FROM TeacherInfo T LEFT JOIN TeachSchedule S ON T.TeacherID = S.TeacherID GROUP BY T.TeacherID, T.TeacherName, S.ScheduleYear, S.ScheduleMonth;逻辑说明:视图把Join和Group By固定下来,DAL层查询时只需要写SELECT * FROM v_TeacherMonthSalary WHERE TeacherID=@id,查询语句简洁很多。LEFT JOIN加上ISNULL保证没有课时记录的教师也能显示,汇总金额为0。这是一个典型的空间换时间做法,用一点冗余换来报表SQL的可读性。
这种视图在SQL Server里默认不索引,数据量小可以直接用;将来外聘教师数量涨到几千条而且按月查询频繁时,再考虑改成索引视图或直接在C#端做内存汇总。回到这个项目,视图已经是够用的方案。
4.3 初始化数据:管理员账号不是硬编码在代码里
UserInfo表里有一条默认管理员账号,插入脚本常见是这样:
INSERT INTO UserInfo (UserName, PasswordHash, UserRole) VALUES (N'admin', N'e10adc3949ba59abbe56e057f20f883e', 1);逻辑说明:PasswordHash存的是MD5哈希值。123456经过MD5计算就是e10adc3949ba59abbe56e057f20f883e,登录时把用户输入的密码也做一次MD5,再和库里比对。这样即使数据库泄露,也不会直接暴露明文密码。当然MD5现在不算安全,生产环境建议改用SHA256加盐,但作为学习项目,这个写法能让你理解哈希存储的用意。
参数说明:UserRole字段里1表示管理员,2表示普通教务员。你在二次开发时可以把这个字段扩展成权限集合,或者直接改成角色ID关联权限表。默认账号写进SQL脚本比在代码里写死要好,因为换环境部署时只需要执行一下脚本,不需要重新编译程序。
这个初始化脚本还有一个隐藏作用:数据库连不上时,可以用它检查连接字符串是否正常。如果脚本执行成功后登录依然失败,问题就出在程序代码里,而不是数据库本身。
5. 运行与部署避坑:四个高频问题的现象、原因与解决
5.1 登录按钮点了就报“无法打开数据库”
现象:程序能启动,输入admin和密码后弹窗显示“在与SQL Server建立连接时发生网络相关错误”或“无法打开登录所请求的数据库”。
原因:九成是App.config里的连接字符串和本机SQL Server实例不匹配。作者开发时用的机器是.\SQLEXPRESS,你电脑上装的是默认实例MSSQLSERVER,或者没有启用混合登录模式。
解决:打开UI层的App.config,把Data Source改成你的实例名;如果是Windows身份验证,改成Integrated Security=True。最好先用Visual Studio服务器资源管理器手动连接一次,确认能连通再跑程序。这个操作能解决80%的“跑不起来”问题,剩下的两成要去看SQL Server服务有没有启动。
5.2 DataGridView里改了数据,重启后恢复原样
现象:窗体上DataGridView能直接编辑、删除行,程序运行时也提示操作成功,但重启程序后数据还是旧的。
原因:这是桌面项目里常见的踩坑点。很多初学写法是直接把DataTable绑定到DataGridView,编辑完没有调用SqlDataAdapter.Update方法。DataGridView只是内存视图,改的是DataTable里的数据,数据库并没有收到任何UPDATE语句。
解决:需要用SqlDataAdapter配合SqlCommandBuilder来更新。做法是先创建adapter,然后用SqlCommandBuilder(adapter)自动生成增删改命令,最后调用adapter.Update(dataTable)。加上这一步,数据库里的改动才真正落库。如果项目里用的是SqlHelper这种简易封装,说明它本来就不支持自动更新,要在DAL层单独写UpdateTeacher方法,把DataGridView当前行的字段取出来,逐字段执行UPDATE。
5.3 界面显示中文正常,数据库里却全是问号
现象:从界面录入的外聘教师姓名,存到SQL Server里变成“???”,但直接写SQL插入不会这样。
原因:数据链路里编码不一致。常见有两个来源:一是数据库表字段用的不是Unicode类型,NVARCHAR就不会乱码,VARCHAR字段在中文环境下会因为排序规则不同出现乱码;二是SQL脚本文件本身是ANSI编码,执行时把N前缀丢掉了。
解决:建表时用NVARCHAR类型,写字符串时带上N前缀,比如INSERT INTO TeacherInfo VALUES (N'张三')。另外检查SQL Server数据库的排序规则,建议使用Chinese_PRC_CI_AS。如果你的表已经建好,可以按ALTER TABLE ... ALTER COLUMN把VARCHAR改成NVARCHAR。这个坑在第一次迁移数据库时尤其容易碰到,属于血泪经验。
5.4 本机能跑,把exe拷给同学就打不开
现象:把Debug目录整个拷过去,对方电脑上双击exe报错“System.Data.SqlClient相关类型未找到”,或者直接提示.NET Framework版本过低。
原因:很多同学只拷exe,不拷配置文件和相关DLL;或者项目目标框架是.NET Framework 4.7,而对方电脑只装了4.0。C#程序不是免编译的绿色软件,Debug目录里每个文件都有用,App.config也必须一起带。
解决:拷贝时把整个Debug或Release目录打包发送,不要只拿单个exe。对方机器上需要安装对应版本的.NET Framework运行库,Windows 10以上一般自带4.8,但要确认项目属性里目标框架不高于对方环境。如果对方完全没有环境,可以把发布方式改成“单文件发布”,把运行时一起打包进去。
5.5 附加.mdf数据库文件提示权限不足
现象:通过SSMS附加TeacherDB.mdf时,报“无法打开物理文件,拒绝访问”。
原因:mdf文件放在Program Files、系统temp目录等Windows保护目录下,SQL Server服务账户对这些目录没有读写权限。很多人在这里折腾了整整一个下午,最后发现根本不是SQL语句的问题,而是文件搬家就解决了。
解决:把mdf和ldf文件移动到一个普通目录,比如项目根目录下的Database文件夹,再在SSMS里附加。或者右键文件给SQL服务的启动账户加完全控制权限。如果你用的是localdb,通常不存在这个问题;只有SQL Server服务代理模式下才会遇到。
6. 二次开发改造:把外聘教师系统改成你自己的业务模型
6.1 改造点:从“课时费”扩展到“项目津贴”
拿到这个资源,最容易上手的改造方向是加一个字段。比如想给外聘教师加“交通补贴”,在TeacherInfo表里加TransportAllowance字段,然后到DAL层新增插入和更新语句,UI窗体加一个TextBox。这个链路只要走一遍,你对三层架构的理解就算落地了。
如果想做得更有价值,可以把课时费结算改造成“基础课时费加上超额部分阶梯计价”的规则。先在TeachSchedule里增加一个TotalHours字段,然后在存储过程里用CASE WHEN判断超过60课时后单价提高20%。这种改动涉及SQL逻辑、BLL参数和UI展示三层,改完你会对系统边界有更实在的理解。
6.2 改造时的验证顺序
每次改一个功能,我建议按这个顺序验证:先在数据库工具里把SQL语句跑通,再到DAL层写一个测试方法调用,最后回到UI层调BLL。不要在窗体里直接写SQL,也不要一上来就改前端。我会把SqlHelper的ExecuteDataTable重载一版,支持传入CommandType.StoredProcedure,然后在DAL层写一个带返回DataTable的方法。验证的时候只需要在Main函数里临时调用一次,看一眼数据对不对,再删掉测试代码。
下面是一个新增导出Excel的方法骨架,很多人在二次开发时都会用到:
SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "Excel 文件|*.xlsx|Excel 97-2003|*.xls"; if (sfd.ShowDialog() == DialogResult.OK) { // 用NPOI把DataTable写出,不需要本机安装Office }逻辑说明:NPOI是开源库,通过NuGet安装。它的好处是不依赖Office组件,服务器也能导出。把DataTable的列名映射成Excel表头,行数据逐行写入,最后用FileStream保存到用户选择的路径。
参数说明:sfd.Filter指定文件类型对话框里可选的扩展名;DialogResult.OK判断用户是否点了保存按钮。NPOI里XSSFWorkbook对应xlsx格式,HSSFWorkbook对应xls格式,按需选择即可。
从那以后我每次接手别人的rar包,都强制先扒一遍数据库脚本再动代码,不然后面改字段的时候一定会翻车。先看懂表结构,再改逻辑,最后再动界面,这条顺序能帮你省掉好几个晚上。希望这篇《外聘教师管理系统》的解析能让你少走点弯路,希望帮到你。
本文还有配套的精品资源,点击获取