Full-Stack Travel Guide Application Development with SSM, Vue.js, and UniApp
The platform implements a distributed three-tier architecture combining Spring Framework for enterprise-grade backend services, Vue.js for interactive web interfaces, and UniApp for cross-platform mobile deployment. This architecture decouples business logic from presentation layers while maintaining seamless data flow between server and client components.
Backend Implementation with SSM
The server-side stack integrates Spring for dependency management and transaction control, Spring MVC for RESTful endpoint handling, and MyBatis for database abstraction. This configuration provides clear separation between controller logic, service implementations, and data access objects.
@RestController
@RequestMapping("/api/guides")
public class TravelGuideController {
@Autowired
private GuideService guideService;
@GetMapping("/{regionId}")
public ResponseEntity<GuideCollection> fetchRegionalGuides(@PathVariable Long regionId) {
GuideCollection collection = guideService.findByRegion(regionId);
return collection != null ?
ResponseEntity.ok(collection) :
ResponseEntity.notFound().build();
}
@PostMapping
public ResponseEntity<Map<String, Object>> submitNewGuide(@RequestBody GuideSubmission submission) {
Long guideId = guideService.createGuide(submission);
Map<String, Object> response = new HashMap<>();
response.put("guideId", guideId);
response.put("status", "published");
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
}
This controller handles travel guide retrieval and creation, utilizing constructor injection for service dependencies and returning standardized HTTP responses.
Frontend Development with Vue.js
The web interface leverages Vue 3's Composition API for reactive state management and component modularity. The following component demonstrates dynamic rendering of attraction listings with interactive features:
<template>
<div class="itinerary-wrapper">
<header class="region-header">
<h2>{{ destinationTitle }}</h2>
<span class="visit-count">Visitors: {{ trafficStats }}</span>
</header>
<div class="attraction-grid">
<article v-for="site in scenicSpots" :key="site.spotId" class="spot-card">
<h3>{{ site.spotName }}</h3>
<p class="description">{{ site.briefIntro }}</p>
<button @click="toggleDetails(site.spotId)">View Details</button>
</article>
</div>
<button class="load-more" @click="fetchAdditionalSpots">Discover More</button>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
const destinationTitle = ref('Southeast Asia Explorer');
const scenicSpots = ref([]);
const offset = ref(0);
const trafficStats = computed(() => {
return scenicSpots.value.reduce((total, spot) => total + spot.monthlyVisits, 0);
});
const fetchAdditionalSpots = async () => {
const response = await fetch(`/api/guides/spots?start=${offset.value}&limit=10`);
const newData = await response.json();
scenicSpots.value.push(...newData);
offset.value += 10;
};
const toggleDetails = (id) => {
// Navigation logic to detail view
window.location.href = `/details/${id}`;
};
onMounted(() => {
fetchAdditionalSpots();
});
</script>
Cross-Platform Mobile Solution
UniApp serves as the mobile development framework, enabling simultaneous deployment to iOS, Android, and various mini-program platforms. The framework employs Vue.js syntax while providing native rendering capabilities through a custom runtime. Key features include offline map caching, itinerary synchronization, and location-based recommendations utilizing the device's GPS capabilities.
Data Persistence Design
The database layer utilizes MyBatis for SQL mapping and connection pooling. The follwoing schema defines the core entity for travel destinations:
CREATE TABLE `attraction_repository` (
`attraction_id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`display_name` varchar(200) NOT NULL COMMENT 'Tourist spot designation',
`geographic_coords` point NOT NULL COMMENT 'Latitude and longitude',
`ticket_pricing` decimal(10, 2) DEFAULT NULL COMMENT 'Entry fee in local currency',
`visitor_quota` int UNSIGNED DEFAULT 1000 COMMENT 'Maximum daily capacity',
`description_text` text COMMENT 'Detailed introduction',
`established_date` date DEFAULT NULL,
`record_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`attraction_id`),
SPATIAL INDEX `idx_coords` (`geographic_coords`),
KEY `idx_pricing` (`ticket_pricing`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Core tourism attraction data';
Authentication and Authorization
Security implementation utilizes JWT (JSON Web Tokens) with interceptor-based validation. The filter examines incoming requests for valid credentials before granting access to protected resources.
@Component
public class BearerTokenInterceptor extends OncePerRequestFilter {
private static final String AUTH_HEADER = "X-Auth-Token";
@Autowired
private SessionManager sessionManager;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
configureCrossOriginHeaders(response, request);
if (isOptionsRequest(request)) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
if (isPublicEndpoint(request)) {
filterChain.doFilter(request, response);
return;
}
String token = request.getHeader(AUTH_HEADER);
SessionContext context = sessionManager.validateSession(token);
if (context == null) {
rejectUnauthorizedAccess(response);
return;
}
request.setAttribute("userContext", context);
filterChain.doFilter(request, response);
}
private void configureCrossOriginHeaders(HttpServletResponse response, HttpServletRequest request) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Auth-Token, X-Requested-With");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
}
private boolean isOptionsRequest(HttpServletRequest request) {
return "OPTIONS".equalsIgnoreCase(request.getMethod());
}
private boolean isPublicEndpoint(HttpServletRequest request) {
String path = request.getRequestURI();
return path.startsWith("/api/public/") || path.equals("/api/auth/login");
}
private void rejectUnauthorizedAccess(HttpServletResponse response) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Invalid or expired session\"}");
}
}
Quality Assurance Methodology
System validation employs black-box testing strategies focusing on functional requirements without examining internal code structures. Test scenarios simulate real-world usage patterns including concurrent user access, boundary value inputs, and error condition handling.
Authentication Test Scenarios:
| Input Parameters | Expected System Behavior | Actual Outcome | Verification |
|---|---|---|---|
| Valid credentials: user="traveler01", pass="SecurePass123" | Grant access, issue token | Token generated successfully | Pass |
| Invalid password combination | Reject with error message | "Invalid credentials" displayed | Pass |
| Empty authentication header on protected route | Block access, return 401 | 401 Unauthorized returned | Pass |
| Expired session token | Redirect to login prompt | Login redirection triggered | Pass |
Content Management Test Scenarios:
| Operation | Test Data | Expected Result | Status |
|---|---|---|---|
| Create guide | Title: "Tokyo Hidden Gems", Category: "Food" | Record persisted with ID | Pass |
| Update capacity | Attraction ID: 101, New capacity: 500 | Database value updated | Pass |
| Search functionality | Keyword: "museum", Price range: 0-50 | Filtered results returned | Pass |
| Concurrent edits | Two users modifying same record | Optimistic locking prevents conflict | Pass |
The testing protocol validates API endpoints using automated request simulation, verifies database integrity through transaction rollback tests, and confirms frontend responsiveness across device viewports. Performance benchmarks include page load times under 2 seconds and API response latency below 200ms for 95th percentile requests.