汽车租赁行业近年来随着共享经济的发展迎来了爆发式增长。传统的人工管理方式在面对海量车辆调度、订单处理时显得力不从心,经常出现车辆状态更新不及时、订单处理效率低下等问题。作为一名长期从事企业级应用开发的工程师,我曾参与过多个租赁系统的开发,深知一个稳定高效的汽车租赁管理系统对于企业运营的重要性。
这个基于SpringBoot+Vue的汽车租赁管理系统,正是为了解决这些痛点而设计的。系统采用前后端分离架构,后端使用SpringBoot提供RESTful API,前端通过Vue.js实现动态交互,数据库选用MySQL保证数据可靠性。这种技术组合在当前企业级应用中非常主流,特别适合作为毕业设计或课程设计的选题,因为它涵盖了现代Web开发的完整技术栈。
选择SpringBoot作为后端框架主要基于以下几个考虑:
前端选择Vue.js的原因:
数据库选择MySQL的考量:
系统采用典型的三层架构:
关键组件交互流程:
提示:在实际开发中,建议使用Swagger生成API文档,方便前后端协作。
sql复制CREATE TABLE `car_info` (
`car_id` bigint NOT NULL AUTO_INCREMENT,
`car_model` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
`car_plate` varchar(20) COLLATE utf8mb4_general_ci NOT NULL,
`car_status` tinyint NOT NULL DEFAULT '0' COMMENT '0-空闲,1-已租',
`rent_price` decimal(10,2) NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`car_id`),
UNIQUE KEY `idx_car_plate` (`car_plate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
设计要点:
sql复制CREATE TABLE `user_order` (
`order_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`car_id` bigint NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`order_status` tinyint NOT NULL DEFAULT '0' COMMENT '0-未支付,1-已支付,2-已完成',
`total_amount` decimal(10,2) NOT NULL,
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`order_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_car_id` (`car_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
设计考虑:
后端Controller示例:
java复制@RestController
@RequestMapping("/api/car")
public class CarController {
@Autowired
private CarService carService;
@GetMapping("/list")
public Result list(@RequestParam(required = false) Integer status) {
List<Car> cars = carService.queryByStatus(status);
return Result.success(cars);
}
@PostMapping("/add")
public Result add(@Valid @RequestBody Car car) {
if (carService.existsByPlate(car.getCarPlate())) {
return Result.error("车牌号已存在");
}
carService.save(car);
return Result.success();
}
@PostMapping("/updateStatus/{id}/{status}")
public Result updateStatus(@PathVariable Long id,
@PathVariable Integer status) {
carService.updateStatus(id, status);
return Result.success();
}
}
前端Vue组件关键代码:
vue复制<template>
<el-table :data="carList" style="width: 100%">
<el-table-column prop="carModel" label="车型" width="180" />
<el-table-column prop="carPlate" label="车牌号" />
<el-table-column prop="rentPrice" label="日租金" />
<el-table-column label="状态">
<template #default="scope">
<el-tag :type="scope.row.carStatus === 0 ? 'success' : 'danger'">
{{ scope.row.carStatus === 0 ? '空闲' : '已租' }}
</el-tag>
</template>
</el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
carList: []
}
},
created() {
this.fetchCars()
},
methods: {
async fetchCars() {
const res = await this.$http.get('/api/car/list')
this.carList = res.data
}
}
}
</script>
订单创建业务逻辑:
关键代码实现:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private CarMapper carMapper;
@Autowired
private OrderMapper orderMapper;
@Override
@Transactional
public Order createOrder(OrderDTO dto) {
// 1. 检查车辆状态
Car car = carMapper.selectById(dto.getCarId());
if (car == null || car.getStatus() != 0) {
throw new BusinessException("车辆不可租");
}
// 2. 计算租赁天数
long days = ChronoUnit.DAYS.between(
dto.getStartTime().toLocalDate(),
dto.getEndTime().toLocalDate()
);
if (days <= 0) {
throw new BusinessException("租赁时间不合法");
}
// 3. 创建订单
Order order = new Order();
order.setUserId(dto.getUserId());
order.setCarId(dto.getCarId());
order.setStartTime(dto.getStartTime());
order.setEndTime(dto.getEndTime());
order.setTotalAmount(car.getRentPrice().multiply(new BigDecimal(days)));
orderMapper.insert(order);
// 4. 更新车辆状态
car.setStatus(1);
carMapper.updateById(car);
return order;
}
}
JWT配置类:
java复制@Configuration
public class JwtConfig {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expire}")
private Long expire;
@Bean
public JwtUtil jwtUtil() {
return new JwtUtil(secret, expire);
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
JWT工具类核心方法:
java复制public class JwtUtil {
private final String secret;
private final Long expire;
public String generateToken(Long userId, Integer role) {
Date now = new Date();
Date expireDate = new Date(now.getTime() + expire * 1000);
return Jwts.builder()
.setHeaderParam("typ", "JWT")
.setSubject(userId.toString())
.claim("role", role)
.setIssuedAt(now)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Claims getClaims(String token) {
try {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
return null;
}
}
}
缓存车辆信息的实现:
java复制@Service
public class CarServiceImpl implements CarService {
@Autowired
private CarMapper carMapper;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String CACHE_PREFIX = "car:";
@Override
public Car getById(Long id) {
String key = CACHE_PREFIX + id;
Car car = (Car) redisTemplate.opsForValue().get(key);
if (car != null) {
return car;
}
car = carMapper.selectById(id);
if (car != null) {
redisTemplate.opsForValue().set(key, car, 1, TimeUnit.HOURS);
}
return car;
}
@Override
@CacheEvict(key = "#car.carId")
public void update(Car car) {
carMapper.updateById(car);
}
}
bash复制mvn clean package -DskipTests
上传jar包到服务器
启动应用:
bash复制nohup java -jar car-rental.jar --spring.profiles.active=prod > app.log 2>&1 &
nginx复制server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
bash复制npm run build
上传dist目录到服务器
配置Nginx:
nginx复制server {
listen 80;
server_name www.example.com;
root /var/www/car-rental;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://api.example.com;
}
}
SpringBoot配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*")
.maxAge(3600);
}
}
统一日期格式处理:
java复制@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.timeZone(TimeZone.getTimeZone("GMT+8"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
使用数据库乐观锁解决:
java复制@Service
public class OrderServiceImpl implements OrderService {
@Transactional
public Order createOrder(OrderDTO dto) {
// 使用SELECT ... FOR UPDATE加锁
Car car = carMapper.selectForUpdate(dto.getCarId());
if (car.getStatus() != 0) {
throw new BusinessException("车辆已被预订");
}
// ... 创建订单逻辑
// 更新版本号
car.setVersion(car.getVersion() + 1);
carMapper.updateWithVersion(car);
}
}
对应的Mapper XML:
xml复制<update id="updateWithVersion">
UPDATE car_info
SET status = #{status},
version = version + 1
WHERE car_id = #{carId}
AND version = #{version}
</update>
在实际开发中,我建议先从核心功能入手,确保基础业务流程跑通后再考虑扩展功能。对于毕业设计项目,重点应该放在系统设计的合理性和代码质量上,而不是一味追求功能复杂。