1. 项目概述与背景
跑腿代办系统在现代城市生活中扮演着越来越重要的角色。作为一个基于SSM框架开发的业务代办管理系统,它有效连接了有需求的用户和可以提供服务的跑腿人员。这个系统采用JavaWeb技术栈实现,包含管理员、用户和跑腿小哥三种角色,形成了一个完整的服务闭环。
我选择SSM框架(Spring+SpringMVC+MyBatis)作为后端基础,主要考虑到它在企业级JavaWeb开发中的成熟度和灵活性。Spring的IoC和AOP特性让系统架构更加清晰,MyBatis则提供了对SQL的精细控制能力。前端采用Bootstrap+jQuery组合,既能保证响应式布局,又能实现丰富的交互效果。
2. 系统架构与技术选型
2.1 后端技术栈解析
系统采用经典的三层架构:
- 表现层:SpringMVC处理HTTP请求和响应
- 业务逻辑层:Spring管理的Service组件
- 数据访问层:MyBatis实现ORM映射
数据库选用MySQL 5.7,主要考虑因素包括:
- 事务支持完善,适合订单类业务
- 社区活跃,文档丰富
- 与Java生态集成成熟
2.2 前端技术方案
前端页面采用JSP+Bootstrap+jQuery技术组合:
- JSP负责服务端渲染
- Bootstrap 3.x提供响应式布局基础
- jQuery处理DOM操作和AJAX请求
这种组合的优势在于:
- 开发效率高,组件丰富
- 兼容性好,适配各种设备
- 学习曲线平缓,适合快速迭代
3. 核心功能实现细节
3.1 用户管理系统
用户模块包含注册、登录、个人信息管理等功能。密码采用MD5加密存储,关键代码如下:
java复制@RequestMapping(value = "/register.do")
public String register(HttpServletRequest request, User util, Model model) {
// 验证码校验
HttpSession session = request.getSession();
String code = (String) session.getAttribute("code");
String userCode = request.getParameter("code");
if (!code.equals(userCode)) {
model.addAttribute("errMsg", "验证码错误");
return "../register";
}
// 用户名查重
User user = userMapper.getObjectByName(util);
if (null != user) {
model.addAttribute("errMsg", "该用户名已经存在");
return "../register";
}
// 密码加密
util.setS_1(MD5Util.encode(util.getS_1()));
userMapper.insertObject(util);
model.addAttribute("registerMsg", "注册成功!");
return "../login";
}
3.2 订单业务流程实现
订单状态机设计:
- 已发布 → 接单中
- 接单中 → 已完成
- 接单中 → 已取消
关键状态变更逻辑:
java复制@RequestMapping(value = "/saveOrUpdateObject.do")
public String saveOrUpdateObject(HttpServletRequest request, Jied util, Model model) {
if (0 == util.getId()) { // 新建接单
util.setS_0("BH"+System.currentTimeMillis()); // 生成订单编号
util.setS_2("接单中");
jiedMapper.insertObject(util);
// 更新原订单状态
Dingd dingd = dingdMapper.selectObject(util.getDingd().getId());
dingd.setS_6("接单中");
dingdMapper.updateObject(dingd);
}
// ...其他逻辑
}
4. 数据库设计与优化
4.1 主要表结构
-
用户表(user):
- id: 主键
- s_0: 用户名
- s_1: 密码(MD5加密)
- s_2: 真实姓名
- s_11: 用户类型(admin/user/yewu)
-
订单表(dingd):
- id: 主键
- user_id: 关联用户
- s_0: 订单标题
- s_6: 订单状态
-
接单表(jied):
- id: 主键
- dingd_id: 关联订单
- user_id: 关联接单人
- s_1: 接单时间
- s_2: 接单状态
4.2 索引优化方案
为提高查询效率,我们在以下字段建立索引:
- user表的s_0字段(用户名登录用)
- dingd表的user_id字段(用户查询自己订单)
- jied表的dingd_id和user_id字段(订单关联查询)
5. 系统部署与配置
5.1 环境准备
- JDK 1.8+
- MySQL 5.7+
- Tomcat 8+
- Maven 3.6+
5.2 部署步骤
- 数据库初始化:
sql复制CREATE DATABASE paotui DEFAULT CHARACTER SET utf8;
USE paotui;
SOURCE paotui.sql;
- 修改数据库配置:
properties复制# db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/paotui?useSSL=false
jdbc.username=root
jdbc.password=123456
- Maven构建:
bash复制mvn clean package
- 部署到Tomcat:
- 将target目录下的war包复制到Tomcat的webapps目录
- 启动Tomcat服务
6. 常见问题解决方案
6.1 中文乱码问题
解决方案:
- 确保MySQL字符集为utf8
- 在JDBC连接字符串中添加参数:
properties复制jdbc.url=jdbc:mysql://localhost:3306/paotui?useUnicode=true&characterEncoding=UTF-8 - 在JSP页面头部添加:
jsp复制<%@ page contentType="text/html;charset=UTF-8" language="java" %>
6.2 订单状态同步问题
当多个跑腿小哥同时抢单时,可能出现状态不一致。解决方案:
- 使用数据库乐观锁:
java复制@Update("UPDATE dingd SET s_6=#{status}, version=version+1
WHERE id=#{id} AND version=#{version}")
int updateWithVersion(Dingd dingd);
- 添加事务注解:
java复制@Transactional
public void acceptOrder(Integer orderId, Integer runnerId) {
// 业务逻辑
}
7. 安全防护措施
7.1 XSS防护
在JSP页面中使用JSTL的c:out标签自动转义:
jsp复制<td><c:out value="${user.s_2}"/></td>
7.2 CSRF防护
Spring Security配置CSRF防护:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
7.3 SQL注入防护
坚持使用MyBatis的参数化查询,绝对不要拼接SQL:
xml复制<select id="getObjectList" resultMap="BaseResultMap">
SELECT * FROM user
WHERE s_11 = #{userType}
<if test="name != null">
AND s_2 LIKE CONCAT('%',#{name},'%')
</if>
</select>
8. 性能优化实践
8.1 数据库连接池配置
在Spring配置中使用Druid连接池:
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="initialSize" value="5"/>
<property name="maxActive" value="20"/>
<property name="minIdle" value="5"/>
</bean>
8.2 MyBatis二级缓存
在mapper.xml中启用缓存:
xml复制<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
8.3 静态资源缓存
在SpringMVC配置中添加静态资源缓存:
java复制@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/")
.setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS));
}
9. 扩展与改进方向
9.1 微服务化改造
将系统拆分为:
- 用户服务
- 订单服务
- 接单服务
使用Spring Cloud Alibaba实现服务治理
9.2 引入消息队列
使用RocketMQ处理:
- 订单状态变更通知
- 系统消息推送
- 异步日志记录
9.3 移动端适配
开发微信小程序版本:
- 使用uni-app跨平台框架
- 后端提供RESTful API
- 增加地理位置服务
10. 开发心得与建议
在实际开发过程中,我总结了以下几点经验:
-
事务管理要细致:订单状态变更涉及多表操作,必须保证事务原子性。我采用Spring的@Transactional注解,并特别注意了事务传播行为的设置。
-
参数校验不可少:所有用户输入都必须验证。前端做基础校验,后端做最终校验。推荐使用Hibernate Validator简化校验逻辑。
-
日志记录要全面:关键业务操作如订单创建、状态变更等,都需要记录详细日志。我使用SLF4J+Logback组合,并配置了按天滚动的日志文件。
-
分页查询优化:列表查询一定要做分页。我封装了PageModel组件,统一处理分页参数和结果封装,SQL中使用LIMIT实现物理分页。
-
异常处理统一化:通过@ControllerAdvice实现全局异常处理,将系统异常转换为用户友好的错误提示,同时记录详细错误信息供排查。
这个系统从技术选型到最终上线历时两个月,期间遇到了不少挑战,特别是订单状态同步和性能优化方面。通过这个项目,我深刻体会到良好的架构设计对系统可维护性的重要性。后续计划引入Redis缓存热点数据,进一步提升系统响应速度。