Java实战:城市公园信息管理系统(2025最新技术实现)
随着智慧公园概念的普及,传统的公园管理方式已无法满足现代城市发展需求。本文将基于2025年最新技术栈,提供一套完整的城市公园信息管理系统实操指南,涵盖从环境搭建到核心功能实现的全过程。
一、技术栈升级与环境配置
1. 最新技术选型
考虑到系统性能、开发效率和未来扩展性,我们采用以下技术栈:
- 后端框架:Spring Boot 3.2.0(支持虚拟线程,提升并发处理能力)
- 数据访问:Spring Data JPA + Hibernate 6.4(简化数据操作)
- 前端框架:Vue 3 + Vite 5(更快的构建速度和更好的TypeScript支持)
- 数据库:MySQL 8.3(支持JSON数据类型,优化空间数据处理)
- 安全框架:Spring Security 6.2 + JWT(增强的安全特性)
- API文档:SpringDoc-OpenAPI 2.3(生成OpenAPI 3.0规范文档)
- 部署工具:Docker + Docker Compose(简化部署流程)
2. 开发环境搭建
首先确保安装以下工具:
- JDK 21(必须,支持虚拟线程)
- Node.js 20.x + npm 10.x
- Docker 25.x
- IntelliJ IDEA 2024.2(或其他IDE)
项目初始化命令:
# 创建Spring Boot后端项目
spring init --dependencies=web,data-jpa,mysql,security,validation,prometheus,actuator \
--language=java --java-version=21 --packaging=jar \
--groupId=com.park --artifactId=park-management --name=ParkManagement \
--description="City Park Information Management System" --version=1.0.0
# 创建Vue前端项目
npm create vite@latest park-frontend -- --template vue-ts
cd park-frontend
npm install axios vue-router pinia element-plus @element-plus/icons-vue
二、数据库设计与实现
采用MySQL 8.3的新特性,优化空间数据存储和查询性能。
1. 核心数据表设计
-- 公园基本信息表(使用新的JSON类型存储额外属性)
CREATE TABLE parks (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
area DECIMAL(10,2) NOT NULL COMMENT '面积(公顷)',
location POINT NOT NULL COMMENT '地理位置',
opening_hours VARCHAR(255) NOT NULL,
contact_phone VARCHAR(20),
description TEXT,
extra_attributes JSON, -- 存储动态扩展属性
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_location (location) USING GEO
);
-- 设施表
CREATE TABLE facilities (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
park_id BIGINT NOT NULL,
name VARCHAR(100) NOT NULL,
type VARCHAR(50) NOT NULL,
status ENUM('normal', 'maintenance', 'closed') DEFAULT 'normal',
location POINT,
last_maintained_at TIMESTAMP,
FOREIGN KEY (park_id) REFERENCES parks(id) ON DELETE CASCADE,
INDEX idx_park_id (park_id)
);
使用MySQL的空间数据类型POINT
存储地理位置,便于后续实现基于位置的查询功能。
2. JPA实体类实现
@Entity
@Table(name = "parks")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Park {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "公园名称不能为空")
private String name;
@NotNull(message = "面积不能为空")
private BigDecimal area;
@NotNull(message = "位置信息不能为空")
@Convert(converter = PointConverter.class) // 自定义转换器
private Point location;
private String openingHours;
private String contactPhone;
private String description;
// 存储额外属性,使用HashMap映射JSON字段
@Column(columnDefinition = "JSON")
private Map<String, Object> extraAttributes;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
// 关联设施
@OneToMany(mappedBy = "park", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Facility> facilities = new ArrayList<>();
}
自定义Point转换器处理空间数据类型:
三、核心功能实现
1. 公园信息管理API
使用Spring Boot 3.2的虚拟线程特性提升并发处理能力:
@RestController
@RequestMapping("/api/v1/parks")
@RequiredArgsConstructor
public class ParkController {
private final ParkService parkService;
// 使用虚拟线程提高并发处理能力
@GetMapping
public ResponseEntity<Page<ParkDTO>> getAllParks(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(required = false) String name) {
// Spring Boot 3.2+ 自动使用虚拟线程执行控制器方法
Page<ParkDTO> parks = parkService.findParks(name, PageRequest.of(page, size));
return ResponseEntity.ok(parks);
}
@GetMapping("/nearby")
public ResponseEntity<List<ParkDTO>> getNearbyParks(
@RequestParam double latitude,
@RequestParam double longitude,
@RequestParam(defaultValue = "2000") double radius) {
List<ParkDTO> parks = parkService.findNearbyParks(latitude, longitude, radius);
return ResponseEntity.ok(parks);
}
@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<ParkDTO> createPark(@Valid @RequestBody ParkCreateDTO parkDTO) {
ParkDTO created = parkService.createPark(parkDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
// 其他API方法...
}
服务层实现(使用Spring Data JPA的空间查询):
@Service
@RequiredArgsConstructor
@Transactional
public class ParkServiceImpl implements ParkService {
private final ParkRepository parkRepository;
private final ParkMapper parkMapper;
@Override
@Transactional(readOnly = true)
public List<ParkDTO> findNearbyParks(double latitude, double longitude, double radius) {
// 创建查询点
Point userLocation = GEOMETRY_FACTORY.createPoint(new Coordinate(longitude, latitude));
// 计算距离(米),使用MySQL的空间函数
List<Park> parks = parkRepository.findByLocationWithin(
userLocation, radius
);
return parks.stream()
.map(parkMapper::toDto)
.collect(Collectors.toList());
}
// 其他方法实现...
}
2. 前端实现(Vue 3 + TypeScript)
使用Composition API实现公园列表和地图展示:
<template>
<div class="park-container">
<el-row :gutter="20">
<el-col :span="8">
<el-input
v-model="searchQuery"
placeholder="搜索公园名称"
clearable
@clear="handleSearch"
@input="handleSearchDebounced"
>
<template #append>
<el-button @click="handleSearch" icon="Search" />
</template>
</el-input>
<el-card class="park-list" v-if="parks.length > 0">
<el-scrollbar height="calc(100vh - 200px)">
<el-row :gutter="10" v-for="park in parks" :key="park.id" class="park-item">
<el-col :span="24">
<el-card @click="showParkDetails(park)">
<h3>{
{ park.name }}</h3>
<p>面积: {
{ park.area }} 公顷</p>
<p>开放时间: {
{ park.openingHours }}</p>
<el-tag :type="getDistanceTagType(park.distance)">{
{ formatDistance(park.distance) }}</el-tag>
</el-card>
</el-col>
</el-row>
</el-scrollbar>
</el-card>
</el-col>
<el-col :span="16">
<div class="map-container">
<!-- 地图组件 -->
<park-map
:parks="parks"
:center="mapCenter"
:user-location="userLocation"
@park-clicked="showParkDetails"
/>
</div>
</el-col>
</el-row>
</div>
</template>
TypeScript逻辑部分:
<script setup lang="ts">
import {
ref, onMounted, computed } from 'vue';
import {
useDebounceFn } from '@vueuse/core';
import ParkMap from '@/components/ParkMap.vue';
import {
getParks, getNearbyParks } from '@/api/park';
import {
ParkDTO } from '@/types/park';
// 状态定义
const searchQuery = ref('');
const parks = ref<ParkDTO[]>([]);
const loading = ref(false);
const userLocation = ref<{
latitude: number, longitude: number} | null>(null);
const mapCenter = ref<{
latitude: number, longitude: number}>({
latitude: 39.9042, // 默认北京坐标
longitude: 116.4074
});
// 防抖处理搜索
const handleSearchDebounced = useDebounceFn(handleSearch, 500);
// 方法定义
async function handleSearch() {
loading.value = true;
try {
if (searchQuery.value) {
// 按名称搜索
const response = await getParks({
name: searchQuery.value });
parks.value = response.data.content;
} else if (userLocation.value) {
// 按当前位置搜索附近公园
const response = await getNearbyParks({
latitude: userLocation.value.latitude,
longitude: userLocation.value.longitude,
radius: 2000
});
parks.value = response.data;
}
} catch (error) {
console.error('获取公园信息失败', error);
ElMessage.error('获取公园信息失败,请稍后重试');
} finally {
loading.value = false;
}
}
// 获取用户位置
function getUserLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
userLocation.value = {
latitude: position.coords.latitude,
longitude: position.coords.longitude
};
mapCenter.value = {
...userLocation.value };
handleSearch();
},
(error) => {
console.warn('无法获取位置信息', error);
ElMessage.warning('无法获取位置信息,将显示默认区域公园');
handleSearch();
}
);
} else {
ElMessage.warning('您的浏览器不支持地理位置服务');
handleSearch();
}
}
// 格式化距离显示
function formatDistance(meters: number): string {
if (meters < 1000) {
return `${
Math.round(meters)}米`;
} else {
return `${
(meters / 1000).toFixed(1)}公里`;
}
}
// 根据距离返回标签类型
function getDistanceTagType(meters: number): string {
if (meters < 500) return 'success';
if (meters < 1000) return 'warning';
return 'info';
}
// 生命周期钩子
onMounted(() => {
getUserLocation();
});
</script>
3. 安全配置(Spring Security 6.2)
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
.requestMatchers(HttpMethod.GET, "/api/v1/parks/**").permitAll()
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
.cors(cors -> cors.configurationSource(corsConfigurationSource()));
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type"));
configuration.setExposedHeaders(Arrays.asList("Authorization"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
四、容器化部署配置
使用Docker Compose实现一键部署:
后端Dockerfile:
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/park-management-1.0.0.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
前端Dockerfile:
# 构建阶段
FROM node:20-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
五、系统扩展与优化建议
性能优化:
- 使用Redis缓存热门公园信息和用户会话
- 实现数据库读写分离,提高查询性能
- 对图片等静态资源使用CDN加速
功能扩展:
- 集成天气API,显示公园实时天气
- 添加预约管理模块,支持公园内设施预约
- 实现环境监测数据采集与展示(空气质量、噪音等)
安全增强:
- 实现API请求限流,防止恶意攻击
- 添加数据备份与恢复机制
- 定期进行安全审计和漏洞扫描
通过本实操指南,你可以基于最新的Java技术栈构建一个功能完善、性能优异的城市公园信息管理系统。该系统不仅能满足基本的公园信息管理需求,还具备良好的扩展性,可根据实际需求进一步增强功能。
Java 实战开发,城市公园信息管理系统,2025 最新技术,技术落地流程,管理系统开发,Java 项目实战,公园管理系统,全流程解析,Java 技术应用,企业级系统开发,数字化管理系统,Java 实战案例,信息系统搭建,2025 Java 框架,公园信息化开发
代码获取方式
https://pan.quark.cn/s/14fcf913bae6