简介:一款基于ASP的网页版报修系统,面向企事业单位后勤、学校及物业等场景,帮助管理员快速搭建线上报修平台,让用户在线提交维修申请并跟踪处理进度。压缩包共52个文件,整体仅793KB,以ASP动态页面为主,辅以JS交互脚本、CSS样式表、HTM页面和JPG/GIF图片素材,另有IIS配置工具与使用说明,解压后即可按文档部署调试。系统覆盖用户注册登录、报修单填写、后台管理、留言反馈等常用环节,模块划分清晰,适合有ASP基础的学习者参考其前后台实现思路;描述中提到功能强大、易上手,但也存在一些可优化之处,因此也适合二次开发时对照改进。已有88人学习下载,对想了解传统ASP报修系统结构或需要轻量级内网报修方案的用户,是一份实用的入门资料。
1. 报修系统baoxiu.rar:一套仍在运行的ASP+Access报修台
解压开baoxiu.rar,里面不是漂亮的 Ant Design 页面,也没有前后端分离的工程结构,而是一排排.asp、.js和.css。这是一套典型的 Windows IIS + ASP + Access 老式网上报修系统,放在企业内网或者学校机房,够用但不完美。它的核心链路很短:用户注册登录,提交维修单,管理员在admin/houtai.asp里看到待处理列表,编辑状态、填写处理意见,用户再回首页看结果。强在逻辑直白,所有处理过程都摊在代码里;弱在 SQL 拼接、验证码形同虚设、Access 并发写时容易报错。但正因为老,反而适合用来拆解报修系统的流程设计,或者作为内部小工具快速改一版上线。下面从部署到改坑,一层层说透。
2. 解压与部署:IIS下配置baoxiu报修系统的目录权限与数据库连接
2.1 先看清压缩包里的文件布局
baoxiu.rar解压后,根目录下是站点主文件,admin目录装后台,images放图片,js里是count.js、date.js这类前端脚本。核心文件的作用先列出来,方便后面对照:
| 文件 | 角色 | 说明 |
|---|---|---|
conn.asp | 数据库连接 | 几乎每个页面都会 include,负责打开 Access 连接 |
conn2.asp | 第二连接 | 用于后台统计、按日期查询等独立数据链路 |
index.asp | 前台首页 | 展示报修入口、公告和维修状态 |
weixiu.asp | 报修提交 | 接收表单并写入维修记录 |
login.asp | 登录 | 校验用户密码,写入 session |
reg.asp | 注册 | 新用户注册,配合regsubmit.asp完成落库 |
admin/houtai.asp | 后台首页 | 管理员登录后的待办列表 |
admin/lyedit.asp | 维修单编辑 | 修改内容、转状态、写处理结果 |
admin/dele_ly.asp | 维修单删除 | 按 id 删除记录 |
admin/adduser.asp | 用户管理 | 新增后台账号或普通用户 |
style.css/type.css | 样式 | 控制整体界面布局和表单样式 |
老系统没有web.config,也没有applicationHost.config级别的配置,所以部署重点全在 IIS 设置和文件权限上。
2.2 在 IIS 上部署:让 .asp 正常执行
先假设你已经把目录复制到C:\inetpub\wwwroot\baoxiu。在 IIS 管理器里右键创建应用程序,或者直接作为虚拟目录映射过去。关键点有两个:脚本执行权限必须选“纯脚本”,默认应用程序池要支持 ASP。如果 IIS 还没装 ASP 模块,可以先用 PowerShell 确认:
Get-WindowsFeature Web-ASP状态是Installed就可以继续。如果缺失,补装后重置 IIS:
Install-WindowsFeature Web-ASP iisreset这里Web-ASP指的是 IIS 的 ASP 功能角色,不是某个第三方组件。装完后要把站点根目录的权限放开给IIS_IUSRS,否则访问时会弹 500.19 或“无法识别该 URI 方案”。右键目录 -> 安全 -> 编辑,给IIS_IUSRS至少“读取和执行”权限。
2.3 conn.asp:Access 连接字符串的参数拆解
这套系统里几乎所有页面顶部都会 include 一个conn.asp,它负责创建 ADODB.Connection。老代码典型写法:
<% Dim conn, db, connstr db = "data/baoxiu.mdb" connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Server.MapPath(db) Set conn = Server.CreateObject("ADODB.Connection") conn.Open connstr %>db是数据库相对站点根目录的路径,Server.MapPath会把虚拟路径映射成物理路径。注意Provider有两种:Jet 4.0 对应 Access 2003 及以下的.mdb文件;如果你拿到的数据库是.accdb格式,要改用Microsoft.ACE.OLEDB.12.0。在 64 位操作系统上,老系统经常报“未在本地计算机上注册 Microsoft.Jet.OLEDB.4.0”,此时不需要换代码,直接到 IIS 应用程序池里把“启用 32 位应用程序”设为True,或者单独装 Access Database Engine 2010 的 64 位版本。
conn2.asp里一般也写着类似的连接串,它存在的意义是和conn.asp保持两个独立连接。我在查询日期页面看到它被part_star.asp调用,避免高频读取阻塞主连接写库。如果你完全不需要双连接,可以统一改成调用同一个连接对象。
2.4 目录权限与 Access 并发写锁
Access 在 IIS 下要求进程账户对数据库文件有写权限,否则执行update时报“不能更新。数据库或对象为只读”。建议按最小权限给:
- 站点根目录:
IUSR和IIS_IUSRS只给“读取和执行”,防止用户改源码; - 数据库所在目录:单独给“写入”权限,Access 写库时会生成
.ldb锁文件,写不进去会提示“文件正在使用”; admin目录:关闭目录浏览,防止有人直接列源码文件。
到这里,访问http://localhost/baoxiu/index.asp如果正常显示,说明 ASP 解析没问题,接下来测报修提交即可。如果报错,优先看事件查看器,错误大多指向数据库路径或 Provider 注册。
3. 报修流程拆解:从index.asp到weixiu.asp的表单处理与状态流转
3.1 一个文件承担两个角色:显示表单和处理提交
index.asp通过<!--#include file="top.asp"-->引入公共头部,把登录入口、报修入口和最新状态放到一张页面上。用户点“我要报修”进入weixiu.asp,但真正有意思的是weixiu.asp内部根据Request("action")分流。
<% If Request("action") = "save" Then title = Trim(Request("title")) content = Trim(Request("content")) sql = "insert into repair(title, content, username, submit_time, status) values('" & title & "', '" & content & "', '" & Session("username") & "', Now(), 0)" conn.Execute sql Response.Redirect "index.asp?ok=1" Else %> <form method="post" action="weixiu.asp?action=save"> <input type="text" name="title" /> <textarea name="content"></textarea> <input type="submit" value="提交报修" /> </form> <% End If %>这段代码里,action=save是判断条件,只有确实保存时才执行insert,否则就显示 HTML 表单。这样的好处是减少一个中间页面,坏处是 URL 参数直接决定了逻辑分支,扫代码时不容易一眼找到入口。Now()是 Access 的时间函数,status字段默认写 0,表示刚提交、未处理。Session("username")用来标记报修人,但如果用户没登录就访问这个页面,会写入空字符串,所以我在实际部署时会在文件开头加一行:
if Session("username") = "" then Response.Redirect "login.asp?from=weixiu"同样,Request("title")和Request("content")没有做长度限制,数据库表如果给字段定义了长度限制,超长内容会直接报错。可以在前端maxlength控制,但后端也要Len()判断一次。
3.2 维修单的状态流转:数字背后的意义
从后台校验代码推断,维修单表里有一个status字段,常见的映射关系是:
| status | 含义 |
|---|---|
| 0 | 待处理 |
| 1 | 处理中 |
| 2 | 已完成 |
admin/houtai.asp会优先列出status=0的记录,管理员点击处理时进入lyedit.asp,改状态并写处理内容。一般更新语句长下面这样:
<% id = CLng(Request("id")) newstatus = CInt(Request("status")) sql = "update repair set status = " & newstatus & ", handler = '" & Session("admin") & "' where id = " & id conn.Execute sql Response.Redirect "houtai.asp" %>这里的CLng和CInt是把输入参数按整数处理,能挡掉一部分不带数字的输入。但handler字段直接拼接了 session 里的管理员名,一旦 session 被伪造,会写进任意文本。所以我改成先对newstatus做白名单判断,只允许 0、1、2 三个值,不在范围内就跳回后台。
3.3 编辑、删除与防手滑
lyedit.asp的编辑逻辑复杂些,它先把维修单的原始内容select出来,显示在表单里,管理员填写处理意见后,再提交回去更新。dele_ly.asp则很简单,甚至有点危险:
<% id = Request("id") conn.Execute "delete from repair where id = " & id Response.Redirect "houtai.asp" %>这段代码没做权限校验,也没做类型转换,任何人只要知道dele_ly.asp?id=3的格式,就能删任意记录。我改造时会加一个“确认删除”页面,或者至少判断来源页面是本机后台:
if InStr(LCase(Request.ServerVariables("HTTP_REFERER")), "houtai.asp") = 0 then Response.Write "非法操作" Response.End end if但HTTP_REFERER可以伪造,这只是防手滑,不是安全机制。真正要防,还得靠第 4 章讲的 session 校验。
3.4 按日期查询的经典写法
day.htm是一个静态页,里面放一个日期输入框,提交到part_star.asp,再用conn2.asp查询当天记录。Access 查询日期数据时,日期常量要用#包裹,不能像 SQL Server 那样用单引号:
<% d = Request("day") if IsDate(d) then sql = "select * from repair where submit_time >= #" & d & "# and submit_time < #" & DateAdd("d", 1, d) & "#" end if %>IsDate先验证这是合法日期,避免非法字符串破坏 SQL;DateAdd("d", 1, d)取第二天的零点,这样能把某天 00:00:00 到 23:59:59 之间的所有记录都框进来。这种写法在 MySQL 里就得换DATE()函数,属于典型的 Access 迁移踩坑点。
4. 用户与权限:reg.asp注册、login.asp登录以及session鉴权的实现
4.1 注册页与新用户落地
reg.asp负责展示注册表单,regsubmit.asp接收表单参数并写用户表。为了防止机器人,系统用yanzheng.asp生成验证码,并把验证码字符存到 session:
' yanzheng.asp 片段 session("checkcode") = rndcode response.binarywrite ... ' 输出验证码图片regsubmit.asp里比较用户输入和session("checkcode")。这里有个很隐蔽的问题:如果页面启用了缓存,或者用户打开注册页很久才提交,session 中的验证码可能已过期,导致反复提示“验证码错误”。我一般把这个 session 的过期时间设成 10 分钟,并在注册成功时立即清掉:
session("checkcode") = ""另一个细节是注册表单提交的密码,老系统通常用自定义 MD5 函数加密,但要注意该函数返回的是 16 位还是 32 位 MD5。注册和登录两处用的必须是同一个函数,否则会出现注册成功但登录失败的诡异现象。
4.2 login.asp 登录验证与 session 初始化
登录页的逻辑并不复杂,查用户表,匹配则把用户名、用户 ID 写入 session,然后跳转首页。这段代码我在好几个系统里都见到过:
<% u = Trim(Request("username")) p = MD5(Trim(Request("password"))) sql = "select * from users where username = '" & u & "' and password = '" & p & "'" set rs = conn.Execute(sql) if not rs.eof then session("username") = rs("username") session("userid") = rs("id") response.redirect "index.asp" else response.redirect "login.asp?err=1" end if %>注意MD5在这里是自定义函数,不是 VBScript 内置函数。很多老项目把 MD5 实现写在一个单独md5.asp里,如果页面没有 include 它就会报“缺少函数”。session("userid")用来在报修单上记录用户,比直接用字符串用户名更稳定,因为用户名可被注册页修改。
4.3 后台管理员鉴权:admin 目录的 session 检查
后台admin目录下每个页面都需要验证管理员身份,但 ASP 不会自动做这件事。标准做法是在后台公共头部 include 一个admin_check.asp,比如在houtai.asp最顶部:
<!--#include file="admin_check.asp"-->admin_check.asp内容:
<% if session("admin") = "" then response.redirect "../login.asp?from=admin" end if %>如果只是普通用户登录但没进后台,session("admin")为空,瞬间被弹回登录页。adduser.asp是管理员的用户管理页面,里面有新增用户、编辑用户权限的功能。这里需要警惕:如果这个页面没有做上面的 session 检查,任何知道路径的人都可以加一个管理员。这也是我拿到这套系统后第一个动手补的位置。
4.4 退出与超时:logout.asp 和 timeout.htm
logout.asp负责清 session,标准写法:
<% session.Contents.RemoveAll() session.Abandon() response.redirect "login.asp" %>这里有个经验:如果只写session.Abandon(),在同一个响应周期内,某些旧 session 变量依然还能读出来,所以先RemoveAll再Abandon更稳妥。timeout.htm是 session 超时后的提示页,IIS 默认 ASP session 超时是 20 分钟,可在应用程序池或global.asa里改更长。但这套系统没有global.asa,所以我只好在conn.asp里顺手设置了Session.Timeout = 30。
5. 把老系统改到顺手:乱码、注入、分页三个关键改动
5.1 中文乱码:从页面编码到数据库排序
老系统在简体中文 Windows 上默认用 GBK,但现在的浏览器基本默认 UTF-8,不统一就会出现“鏂囦欢”这类乱码。第一步是给每个 ASP 页面顶部加上:
<%@ Language="VBScript" CodePage=65001 %> <% Response.CodePage = 65001 Response.Charset = "utf-8" %>CodePage=65001让服务器把 ASP 内嵌的字符串按 UTF-8 发送,Response.Charset同时设置 HTTP 头里的字符集。如果数据库里的中文已经乱掉了,那要先把 Access 文本字段改成“文本”类型,并确认字段的 Unicode 压缩属性是“是”。Access 本身用 Unicode 存储文本,所以只要在写入前保证接收到的字节流是 UTF-8,乱码问题基本能压住。
5.2 参数化查询:别让 SQL 注入继续裸奔
第 3、4 章里出现的& Request("id") &拼接形式,在旧代码里到处都是。最廉价的改动是给所有取数字参数的位置都加上CLng,让非数字内容直接抛错。但真正的补法是重构成 ADO 参数化查询:
<% set cmd = Server.CreateObject("ADODB.Command") cmd.ActiveConnection = conn cmd.CommandText = "select * from users where username = ? and password = ?" cmd.Parameters.Append cmd.CreateParameter("u", 200, 1, 50) cmd.Parameters.Append cmd.CreateParameter("p", 200, 1, 32) cmd.Parameters.Item(0).Value = u cmd.Parameters.Item(1).Value = p set rs = cmd.Execute %>这里200是adVarChar类型,1是adParamInput,50和32是字段长度。?是 ADO Command 里的占位符,参数按顺序匹配。注意 Access 的 OLEDB 提供程序对?的解析有限制,如果一条 SQL 里有多个?,必须保证参数类型和顺序完全对应。改成参数化之后,用户名输入' or '1'='1只会被当成普通字符串,不会再破坏查询语义。
5.3 给维修单列表加分页
后台houtai.asp如果不分页,记录一多整个页面就卡死。加一个经典游标分页:
<% page = CInt(Request("page")) if page < 1 then page = 1 perpage = 15 sql = "select * from repair order by id desc" set rs = Server.CreateObject("ADODB.Recordset") rs.CursorLocation = 3 rs.Open sql, conn, 3, 1 rs.PageSize = perpage rs.AbsolutePage = page %>CursorLocation=3是adUseClient,客户端游标打开后才有AbsolutePage属性可用。rs.PageSize设置每页条数,rs.AbsolutePage直接跳到指定页。如果不用客户端游标,AbsolutePage会失效或报错。输出时用一个计数器控制序号,写完一页就自动断开。整个分页逻辑封装成子函数,比在每个页面上复制粘贴要省心。
本文还有配套的精品资源,点击获取