ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JavaWeb实战:JSP+Servlet+SQL Server住宅小区车辆管理系统开发指南

JavaWeb实战:JSP+Servlet+SQL Server住宅小区车辆管理系统开发指南 简介面向毕业设计场景的住宅小区车辆管理系统源码工具包基于JSP、Servlet与SQLServer构建适合计算机专业学生完成课程设计或毕业设计时参考。系统覆盖个人中心、用户管理、出入管理员管理、车辆进出管理、车位管理、车位预定管理、网站设定管理等模块页面采用JSP数据库为SQLServer兼容JDK1.8与Eclipse、MyEclipse等常用IDE。压缩包共638个文件约23MB包含Java源码、JSP页面、SQL数据库脚本、配置文档、环境工具包及安装教程其中class与jar文件支撑后端逻辑gif、png等图片用于界面展示另有少量视频辅助演示。目前已有116人浏览学习适合需要快速搭建同类系统、梳理毕设代码结构与部署流程的读者。除完整源码外还附带了基于相同框架项目的安装教程能有效减少环境配置踩坑提升项目运行成功率。1. 毕业设计javajsp住宅小区车辆管理系统sqlserver-qlkrp源码工具包到底要交付什么住宅小区车辆管理系统是Java Web毕业设计里出现频率极高的选题原因很简单业务边界清晰、数据表关系不复杂、又有足够的前后端交互点可以展示。但很多同学拿到这套题为“javajsp住宅小区车辆管理系统sqlserver-qlkrp源码工具包”的项目后第一反应是先把源码导入IDE跑起来结果往往卡在JDK版本不匹配、SQL Server驱动连不上、JSP页面报了500错误这类最基础的问题上。先说清楚这套课题的名字怎么拆。javajsp指技术栈Java作为后端语言JSP作为视图层模板sqlserver指数据库使用微软的SQL Server而不是MySQLqlkrp是压缩包名里的一个标识通常对应打包人的编号或内部版本标记不需要深究源码工具包意味着交付物里除了web工程的源码还应该有数据库脚本、部署说明、可能还有答辩用的文档模板。整套课题本质上是一个带权限区分管理员/业主/安保的车辆进出管理闭环核心表大概只有五六张车位信息、业主车辆登记、进出场记录、月租缴费流水、系统用户。这套课题的价值在于它给了你一个完整的、能直接修改的Web工程骨架而不是一个只有页面没有业务逻辑的静态模板。接下来的章节我会按真实的开发顺序来拆解先建库建表、再打通JDBC访问层、然后写Servlet和JSP页面、最后把车辆进出和计费业务跑通并给出部署和排错建议。每段配置和代码都会直接对应SQL Server 2008 R2到2019这个常见范围因为毕业设计环境里用2012和2016的比例最高。2. SQL Server数据库设计与JDBC访问层搭建2.1 用一条建库脚本把整个系统的表结构立起来拿到源码工具包后第一件事不是看Java代码而是先把数据库脚本跑通。这套课题的SQL脚本一般放在sql目录或者db目录下文件名叫vehicle_system.sql或init.sql。如果你用的是SQL Server Management StudioSSMS直接打开脚本文件选择当前连接的实例执行即可。但这里有一个最常见的坑脚本里如果有USE master和GO批处理符号必须在SSMS的SQLCMD模式下执行否则会报语法错误。下面是一个适用于SQL Server 2012及以上版本的建库脚本核心片段字段命名和源码工具包里的Java实体类保持了一致CREATE DATABASE VehicleDB; GO USE VehicleDB; GO CREATE TABLE tb_user ( uid INT IDENTITY(1,1) PRIMARY KEY, username NVARCHAR(30) NOT NULL UNIQUE, password NVARCHAR(64) NOT NULL, role INT NOT NULL DEFAULT 2, -- 1管理员 2安保 3业主 realname NVARCHAR(30) ); CREATE TABLE tb_owner ( owner_id INT IDENTITY(1,1) PRIMARY KEY, uid INT FOREIGN KEY REFERENCES tb_user(uid), owner_name NVARCHAR(30), phone VARCHAR(20), house_no NVARCHAR(50) ); CREATE TABLE tb_car ( car_id INT IDENTITY(1,1) PRIMARY KEY, owner_id INT FOREIGN KEY REFERENCES tb_owner(owner_id), plate_no NVARCHAR(15) NOT NULL, car_brand NVARCHAR(30), car_color NVARCHAR(20), is_monthly INT DEFAULT 1, -- 是否月租车 1是 0否 monthly_start DATE, monthly_end DATE ); CREATE TABLE tb_parking_space ( space_id INT IDENTITY(1,1) PRIMARY KEY, space_no NVARCHAR(20) NOT NULL UNIQUE, area_name NVARCHAR(30), status INT DEFAULT 0 -- 0空闲 1占用 ); CREATE TABLE tb_entry_log ( log_id INT IDENTITY(1,1) PRIMARY KEY, plate_no NVARCHAR(15) NOT NULL, entry_time DATETIME, exit_time DATETIME, space_no NVARCHAR(20), fee DECIMAL(10,2) DEFAULT 0, status INT DEFAULT 1 -- 1在场 2已离场 );这段脚本的逻辑说明tb_user表用role字段区分三种角色密码字段留了NVARCHAR(64)是为了能容纳MD5加盐后的密文tb_car表通过owner_id关联业主is_monthly字段决定这辆车是月租还是临时车tb_entry_log表同时记录了入场时间、出场时间、占用车位号和费用是系统里数据量增长最快的表也是后面做统计报表的核心数据源。需要注意源码工具包里如果带了tb_owner和tb_user的关联说明登录用户信息和业主信息是分离的这个设计比只弄一张用户表更合理答辩时能解释清楚就是加分项。如果脚本里字段名和你用的源码有出入下载包通常会附带一个数据库设计说明.doc以那个文档为准修改实体类字段即可。2.2 JDBC连接SQL Server的驱动版本选型和连接池配置Java连接SQL Server的JDBC驱动有两种微软官方提供的mssql-jdbc和第三方的jtds。毕业设计环境里SQL Server 2008和2012偏多老牌的sqljdbc4.jar足够用但如果你用的是SQL Server 2017以上版本推荐用微软新的mssql-jdbc-9.4.0.jre8.jar这个版本兼容性强而且支持TLS加密连接。在Eclipse或IDEA里把驱动jar包放到WebContent/WEB-INF/lib目录下后写一个数据库连接工具类。很多新手会直接在每个Servlet里写一遍连接代码这是最容易出现连接泄漏的做法。更可靠的方案是做一个静态的单例连接管理器package com.qlkrp.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtil { private static final String DRIVER com.microsoft.sqlserver.jdbc.SQLServerDriver; private static final String URL jdbc:sqlserver://localhost:1433;DatabaseNameVehicleDB;encryptfalse;trustServerCertificatetrue; private static final String USER sa; private static final String PASSWORD 123456; static { try { Class.forName(DRIVER); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(SQL Server JDBC驱动加载失败检查lib目录下jar包); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, java.sql.Statement stmt, java.sql.ResultSet rs) { try { if (rs ! null) rs.close(); } catch (SQLException e) {} try { if (stmt ! null) stmt.close(); } catch (SQLException e) {} try { if (conn ! null) conn.close(); } catch (SQLException e) {} } }这段代码有两点值得说明。第一URL字符串里的encryptfalse和trustServerCertificatetrue是SQL Server 2019才需要的参数JDBC 9.x驱动默认要求加密连接不加这两个参数会直接报The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer在SQL Server 2012上连JDBC 7.x驱动时就不会遇到这个问题。第二这里没有使用连接池是因为毕业设计网站的并发量极低每次都通过DriverManager获取连接在性能上不会有任何感知差异但close方法必须把Connection、Statement、ResultSet全部关掉否则SQL Server的连接数会被快速占满。2.3 SQL Server TCP/IP协议未启用的排查套路写好了DBUtil类点击Tomcat启动后往往会遇到java.net.ConnectException: Connection refused: connect。这个报错十有八九不是Java代码写错了而是SQL Server的TCP/IP协议没有打开。打开SQL Server配置管理器找到“SQL Server网络配置”下的“MSSQLSERVER的协议”默认情况下TCP/IP是禁用的右键启用然后重启SQL Server服务。还有一个容易被忽略的问题SQL Server Express版本默认只开启了命名管道没有开启TCP/IP另外Express版本默认监听的是\SQLEXPRESS实例名连接URL要写成jdbc:sqlserver://localhost\\SQLEXPRESS;DatabaseNameVehicleDB反斜杠在Java字符串里要写成双反斜杠。登录认证模式也需要确认在SSMS实例属性里选择“SQL Server和Windows身份验证模式”并执行以下语句启用sa账号ALTER LOGIN sa WITH PASSWORD 你的密码; ALTER LOGIN sa ENABLE; GO最后用命令行验证端口是否在监听telnet localhost 1433如果能进入一个空白光标界面说明端口通了再回头去看Tomcat日志。这一套排查流程能解决九成以上的JDBC连接问题。3. JSP页面架构与数据交互层的核心细节3.1 用JSTL替换JSP里的Java脚本片段这套课题的JSP页面主要分布在WebContent/web目录下常见的页面有login.jsp、car_list.jsp、entry_record.jsp、monthly_fee.jsp等。源码工具包里有相当多的老代码会让JSP页面直接写Java代码块比如% for(int i0;ilist.size();i){ %这种写法的坏处是改个样式都要编译一次Tomcat频繁触发JSP重编译还会导致页面加载慢。更合理的做法是引入JSTL标签库把Java循环和判断全部替换成c:forEach和c:if。页面头部引入两个标签% taglib urihttp://java.sun.com/jsp/jstl/core prefixc % % taglib urihttp://java.sun.com/jsp/jstl/fmt prefixfmt %车辆列表页面的表体部分用JSTL生成要比scriptlet干净得多table classtable table-hover thead tr th车牌号/thth车主姓名/thth车位号/th th入场时间/thth状态/thth操作/th /tr /thead tbody c:forEach items${carList} varcar tr td${car.plateNo}/td td${car.ownerName}/td td${car.spaceNo}/td tdfmt:formatDate value${car.entryTime} patternyyyy-MM-dd HH:mm:ss//td td c:choose c:when test${car.status 1} span classbadge badge-success在场/span /c:when c:otherwise span classbadge badge-secondary已离场/span /c:otherwise /c:choose /td tda hrefCarServlet?actiondetaillogId${car.logId}查看/a/td /tr /c:forEach /tbody /table这里需要注意的是fmt:formatDate标签SQL Server的DATETIME字段取出来后如果直接输出会是一长串浮点数格式的时间戳必须通过JSTL的格式化标签处理。如果页面显示的时间是2025-06-01 10:30:00.0这种带小数秒的格式说明没有使用fmt标签而是直接输出了java.sql.Timestamp对象的toString()结果。3.2 用Servlet处理CUD操作而不是直接在JSP里写JDBC这套源码工具包的设计如果足够规范应该是Servlet JSP的经典MVC模式。也就是浏览器请求发到ServletServlet调用DAO层的方法操作数据库然后把结果放到request或session里通过forward或redirect跳转到JSP页面渲染。以车辆进场登记为例前端表单提交到VehicleServlet?actionentryServlet端的代码结构应该是这样的protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(UTF-8); String action request.getParameter(action); if (entry.equals(action)) { String plateNo request.getParameter(plateNo).trim().toUpperCase(); String spaceNo request.getParameter(spaceNo); // 检查车辆是否已经在场 VehicleDAO dao new VehicleDAO(); if (dao.isCarInPark(plateNo)) { request.setAttribute(errorMsg, 该车牌已在停车场内重复入场登记失败); request.getRequestDispatcher(/web/entry.jsp).forward(request, response); return; } // 查找空闲车位如果没有空闲车位则提示 String availableSpace dao.findAvailableSpace(); if (availableSpace null) { request.setAttribute(errorMsg, 当前无空闲车位); request.getRequestDispatcher(/web/entry.jsp).forward(request, response); return; } boolean success dao.insertEntryLog(plateNo, availableSpace); if (success) { response.sendRedirect(VehicleServlet?actionrecordListpage1); } else { request.setAttribute(errorMsg, 入场登记写入失败检查数据库连接); request.getRequestDispatcher(/web/entry.jsp).forward(request, response); } } }参数说明action参数用来区分同一个Servlet要处理的不同业务操作这是Java Web项目最基础的接口设计模式request.setCharacterEncoding(UTF-8)必须放在获取任何参数之前否则车牌号里的中文或特殊字符会乱码车牌号做了trim().toUpperCase()是为了保证查询时大小写敏感匹配不出问题SQL Server默认排序规则在多数情况下不区分大小写但统一成大写始终是保险的做法。isCarInPark方法对应的SQL语句是SELECT COUNT(*) FROM tb_entry_log WHERE plate_no ? AND status 1返回结果大于0就说明车还没出去。这个逻辑是整个系统防止重复入场的关键防线也是答辩时老师最喜欢问的业务点建议在断言阶段特别讲清楚。3.3 模糊查询的分页实现不靠OFFSET FETCH也能做JSP页面上通常有一个按车牌号搜索的输入框源码里对应的DAO层SQL大致是SELECT TOP 10 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY entry_time DESC) AS row_num, * FROM tb_entry_log WHERE plate_no LIKE % ? % ) AS t WHERE t.row_num 0这里使用ROW_NUMBER()窗口函数配合TOP和子查询做分页是兼容SQL Server 2008的写法。如果你的数据库是SQL Server 2012以上版本可以换成更简洁的ORDER BY entry_time DESC OFFSET ? ROWS FETCH NEXT 10 ROWS ONLY。JSP页面上的搜索表单和分页导航条控制方式如下表单的method写成getaction指向同一个VehicleServlet把搜索关键词放在keyword参数里页码放在page参数里。访问URL会呈现为VehicleServlet?actionrecordListkeyword京Apage2的格式。这里有一个容易被忽略的细节——翻页时关键词会丢失。解决办法是在生成下一页链接时把keyword拼回去a hrefVehicleServlet?actionrecordListkeyword${param.keyword}page${currentPage 1}下一页/a通过${param.keyword}可以把上一次请求携带的参数自动带到下一页这是JSP EL表达式自带的参数读取能力不需要在Servlet里额外保存。4. 车辆进出场业务与临时车计费模块的实现4.1 月租车到期判断与临时车计费的双轨逻辑这套课题的核心业务场景是小区门口的车辆进出。车辆入场时系统要判断这个车牌号是已登记的月租车还是临时访客车。月租车的判断逻辑依赖tb_car表中的is_monthly和monthly_end字段如果monthly_end早于当前日期说明月租已过期需要按临时车标准计费。Servlet中处理出场时调用的计费核心代码如下public double calcParkingFee(String plateNo, Timestamp entryTime) { CarInfo car getCarByPlate(plateNo); Timestamp exitTime new Timestamp(System.currentTimeMillis()); long durationMs exitTime.getTime() - entryTime.getTime(); if (car ! null car.getIsMonthly() 1 car.getMonthlyEnd().after(new Date())) { return 0; // 月租有效期内不收费 } // 临时车计费不足一小时按一小时算全天封顶30元 double hours Math.ceil(durationMs / 3600000.0); if (hours 1) hours 1; double fee hours * 5; if (fee 30) fee 30; return fee; }这段代码的计费规则是临时车每小时5元不足1小时按1小时算24小时内封顶30元。参数说明Math.ceil用于向上取整计算出小时数如果停车只有10分钟也要收1小时的费用封顶逻辑通过三元判断截断费用上限。实际项目中这个计费规则通常不是写死在Java代码里而是维护在一张tb_fee_rule表里字段包括id、unit_price、max_per_day、free_minutes等。之所以建议用配置表是因为答辩时如果老师说“我停35分钟怎么算”你就能解释规则在表中可自由调整比改代码再重启Tomcat听起来专业得多。4.2 出场时释放车位和写入离场时间的事务保证出场操作有两个数据变更一是更新tb_entry_log表中的exit_time和fee二是把tb_parking_space表中该车辆的status改回0。这两个操作必须放在一个数据库事务里执行否则会出现“车出去了但车位还被占着”的数据不一致问题。DAO层用以下代码保证原子性public boolean processExit(String exitPlateNo) { Connection conn null; PreparedStatement ps1 null; PreparedStatement ps2 null; ResultSet rs null; boolean flag false; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); // 关闭自动提交开启事务 String findSpace SELECT space_no FROM tb_entry_log WHERE plate_no ? AND status 1; ps1 conn.prepareStatement(findSpace); ps1.setString(1, exitPlateNo); rs ps1.executeQuery(); if (rs.next()) { String spaceNo rs.getString(space_no); String updateLog UPDATE tb_entry_log SET exit_time GETDATE(), status 2 WHERE plate_no ? AND status 1; ps1 conn.prepareStatement(updateLog); ps1.setString(1, exitPlateNo); int rows1 ps1.executeUpdate(); String updateSpace UPDATE tb_parking_space SET status 0 WHERE space_no ?; ps2 conn.prepareStatement(updateSpace); ps2.setString(1, spaceNo); int rows2 ps2.executeUpdate(); if (rows1 0 rows2 0) { conn.commit(); flag true; } else { conn.rollback(); } } else { conn.rollback(); } } catch (SQLException e) { e.printStackTrace(); try { if (conn ! null) conn.rollback(); } catch (SQLException ex) {} } finally { try { if (conn ! null) conn.setAutoCommit(true); } catch (SQLException e) {} DBUtil.close(conn, ps2, rs); } return flag; }事务逻辑说明在conn.setAutoCommit(false)之后所有SQL语句都不会立即生效直到conn.commit()被调用。更新进场记录和释放车位的顺序是固定的——先查出该车牌对应的车位号再更新日志、更新车位。如果第二步失败整个操作回滚保持数据库的原始状态。注意GETDATE()是在数据库端执行取得服务器当前时间与Java端的时间可能有时差如果代码部署在另一台机器上和数据库服务器时间不一致计费时长会有偏差。4.3 用存储过程批量查询车位状态分布如果系统首页需要展示车位整体使用率比如显示“总车位120个已占用87个空闲33个”一条简单的聚合查询就够了。但遇到更复杂的需求——按区域统计车位数、统计每日进出场流量、导出当月收费汇总——这条SQL会越写越长Java代码里拼接动态SQL会非常痛苦。常见的做法是把这类统计逻辑封装成SQL Server存储过程在Java端直接调用{call sp_get_space_stats}。以下是一个适合本课题的车位状态统计存储过程CREATE PROCEDURE sp_get_space_stats AS BEGIN SELECT area_name, COUNT(*) AS total_spaces, SUM(CASE WHEN status 1 THEN 1 ELSE 0 END) AS occupied_spaces, SUM(CASE WHEN status 0 THEN 1 ELSE 0 END) AS free_spaces FROM tb_parking_space GROUP BY area_name; END GOJava端调用该存储过程的代码public ListSpaceStat getSpaceStats() { ListSpaceStat list new ArrayList(); String sql {call sp_get_space_stats}; try (Connection conn DBUtil.getConnection(); CallableStatement cstmt conn.prepareCall(sql); ResultSet rs cstmt.executeQuery()) { while (rs.next()) { SpaceStat stat new SpaceStat(); stat.setAreaName(rs.getString(area_name)); stat.setTotal(rs.getInt(total_spaces)); stat.setOccupied(rs.getInt(occupied_spaces)); stat.setFree(rs.getInt(free_spaces)); list.add(stat); } } catch (SQLException e) { e.printStackTrace(); } return list; }这段代码使用CallableStatement通过JDBC调用存储过程而不是拼接SQL字符串好处是在数据库端可以单独调试存储过程不会因为Java代码改动而频繁重启Tomcat。同时存储过程也天然防SQL注入因为它不接收外部拼接的SQL片段。5. 把整套源码跑起来并解决JSP修改不生效的缓存问题5.1 基于源码工具包创建标准Web工程结构的步骤将qlkrp源码工具包解压后标准的Java Web工程目录结构应该是src目录存放Java源码WebContent或IDEA中的web目录存放JSP页面、CSS、JS、图片、WEB-INF下的web.xml和lib目录。如果你的IDE是Eclipse用File - Import - General - Existing Projects into Workspace导入如果是IDEA选择New - Project from Existing Sources并选择Web模块格式。导入后必须检查的三处配置第一Project Facets里勾选的Dynamic Web Module版本与Tomcat版本是否匹配。Tomcat 8.5对应Dynamic Web Module 3.1Tomcat 9对应4.0版本不一致会在启动时抛出ClassNotFoundException: javax.servlet.ServletException之类的错误。第二lib目录下必须同时存在sqljdbc或mssql-jdbc驱动包、jstl-1.2.jar和standard.jar否则页面上的% taglib %会报错。第三web.xml中的welcome-file是否指向登录页面如果没有配置访问http://localhost:8080/项目名/会显示404。5.2 JSP文件修改后Tomcat不生效的三种原因巡查热搜词里有不少人在搜“jsp改了不生效”这个问题的排查顺序其实非常有套路。第一种情况是Tomcat没有自动重新加载。Eclipse和IDEA内置的Tomcat插件默认热部署配置不同修改JSP页面往往能自动生效但修改了Java类或web.xml必须重启服务。如果改的是JSP却刷不出内容按CtrlF5强制刷新浏览器页面绕开本地缓存。第二种情况是把JSP文件直接丢在了WebContent下但没有通过Tomcat映射访问而是用浏览器打开了JSP文件路径。浏览器打开本地JSP文件时会把JSP当作文本文件显示而不是通过Tomcat解析后生成的HTML。访问地址必须是http://localhost:8080/vehicle_system/web/login.jsp这种格式而不是file:///D:/project/WebContent/web/login.jsp。第三种情况是JSP文件被放在了WEB-INF目录下WEB-INF下的JSP不能通过浏览器直接访问Servlet必须用request.getRequestDispatcher(/WEB-INF/web/login.jsp).forward()才能转发到该页面。这种设计能保护页面不被直接访问利用Session或过滤器做权限控制但初学者容易访问不到而感到困惑。5.3 定义一套10分钟验证系统是否可交付的操作清单源码跑通后不要急着截图写论文先按以下顺序手动验证一遍完整业务流程使用管理员账号登录默认密码在数据库脚本初始化数据里通常是admin/123456。在车位管理页手动添加3个车位在业主管理页录入一个业主信息。为该业主登记一辆车牌号为京A12345的月租车月租截止日期设为下个月。在场内登记页面录入该车牌入场选择车位上屏查看列表状态显示“在场”。模拟一发临时车辆沪B99999入场然后立刻做出场操作核对出场页面计算出的费用是否为5元。用业主账号登录查看个人车辆信息和名下缴费记录。第6步尤其重要。很多毕业设计系统管理员功能完整但业主角色登录后什么都做不了这是逻辑覆盖不全的硬伤。如果源码工具包中的业主角色确实只有查看功能至少要在自己的验收清单里标注清楚避免答辩时被问到“业主能不能预约车位”这类扩展业务时无话可说。5.4 驾驶SQL Server性能调优和JSP导出Excel的小技巧当系统里积累了上万条进出场记录后tb_entry_log表上的查询会开始变慢。配合索引能显著加分CREATE NONCLUSTERED INDEX idx_entry_plate ON tb_entry_log(plate_no); CREATE NONCLUSTERED INDEX idx_entry_time ON tb_entry_log(entry_time DESC);plate_no上的索引加速按车牌搜索车辆是否在场entry_time上的索引加速按日期范围统计报表。这两个索引的字段属于写多读多但查询频率更高的场景。如果执行计划中出现了表格扫描Table Scan那大概率是索引没有建立或查询条件未使用索引字段。另外在JSP页面上导出车辆进出记录为Excel时不推荐用Apache POI去写.xlsx文件——那样要引入大量jar包且代码冗长。利用JSP输出CSV文件配合Excel打开才是更轻量级的方案% response.setContentType(text/csv;charsetUTF-8); response.setHeader(Content-Disposition, attachment;filenamerecords.csv); java.io.PrintWriter outWriter response.getWriter(); outWriter.write(\ufeff); // 避免Excel打开中文乱码 outWriter.println(车牌号,入场时间,出场时间,费用); for (EntryLog log : logList) { outWriter.println(log.getPlateNo() , log.getEntryTime() , log.getExitTime() , log.getFee()); } outWriter.flush(); %这段代码的关键是\ufeff这个不可见字符即BOM头。CSV文件在Excel中打开时默认按ANSI编码解析如果JSP页面输出UTF-8的CSV但不带BOMExcel就会把“京A12345”显示成乱码。而导出按钮的普通操作方式是在JSP页面里放一个a hrefExportServlet?actionxlsx的链接让Servlet设置好请求头后再输出。SQL Server的字符串转数字、多日期取最大值这类SQL写法在这个课题里的落地场景分别是字符串类型车牌转数字比较、从多条缴费记录中查最近到期日。前者可以使用CAST(column AS INT)但如果列中有非数字字符会直接报错稳妥的办法是先用ISNUMERIC(column)1过滤后者可以使用SELECT MAX(monthly_end) FROM tb_car WHERE owner_id。这套“javajsp住宅小区车辆管理系统sqlserver-qlkrp源码工具包”课题的完整度取决于你在数据库设计是否能自洽、角色权限是否能区分、计费逻辑是否能闭环这三个层面下多少功夫。把进出场记录、车位状态、权限拦截这三条主脉络理顺了答辩演示时按正常业务流程一路操作下来系统基本就能站得住。如果JSP页面出现中文乱码优先检查pageEncodingUTF-8和response.setCharacterEncoding(UTF-8)的一致性问题如果SQL Server导出数据在Excel里显示为乱码同样先看文件编码和BOM。收尾前再做一次全量数据库备份答辩演示时使用备份还原的方式启动系统环境能大幅降低数据库文件被误删导致演示失败的风险。本文还有配套的精品资源点击获取
返回列表