在旅游信息化快速发展的背景下,游客对目的地餐饮信息的需求日益精细化,而传统的信息分散模式难以满足这一需求。针对这一痛点,设计并实现了一套集中式的美食信息管理平台。该系统采用经典的JSP+Servlet技术架构,通过MVC模式实现了业务逻辑、数据呈现和用户交互的有效分离。
系统架构分为三个核心层次:表现层使用JSP动态页面技术结合HTML/CSS/JavaScript构建用户界面;控制层通过Servlet组件处理所有前端请求和业务逻辑分发;数据持久层采用JDBC技术实现与MySQL数据库的交互。这种分层架构确保了系统具有良好的可维护性和扩展性。

数据库设计包含7个核心数据表,其中美食信息表的设计体现了系统的核心业务逻辑:
CREATE TABLE food_info (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
price DECIMAL(10,2),
restaurant_id INT,
category_id INT,
image_url VARCHAR(200),
status TINYINT DEFAULT 1,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (restaurant_id) REFERENCES restaurant(id),
FOREIGN KEY (category_id) REFERENCES food_category(id)
);
该表通过外键关联实现数据完整性约束,price字段使用DECIMAL类型确保金额计算的精确性,status字段支持软删除逻辑,时间戳字段自动记录数据变更历史。这种设计为系统的核心功能提供了稳健的数据支撑。
用户管理模块采用角色权限分离机制,管理员和普通用户通过统一的登录入口进行身份验证:
public class UserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
String userType = request.getParameter("userType");
UserDAO userDAO = new UserDAO();
User user = userDAO.validateLogin(username, password, userType);
if(user != null) {
HttpSession session = request.getSession();
session.setAttribute("currentUser", user);
if("admin".equals(userType)) {
response.sendRedirect("admin/dashboard.jsp");
} else {
response.sendRedirect("user/home.jsp");
}
} else {
request.setAttribute("errorMsg", "用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
}

美食信息管理功能实现了完整的CRUD操作链,通过DAO模式封装数据访问逻辑:
public class FoodDAO {
public boolean addFood(Food food) {
String sql = "INSERT INTO food_info(name, description, price, restaurant_id, category_id, image_url) VALUES(?,?,?,?,?,?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, food.getName());
pstmt.setString(2, food.getDescription());
pstmt.setBigDecimal(3, food.getPrice());
pstmt.setInt(4, food.getRestaurantId());
pstmt.setInt(5, food.getCategoryId());
pstmt.setString(6, food.getImageUrl());
return pstmt.executeUpdate() > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public List<Food> getFoodsByCategory(int categoryId) {
List<Food> foodList = new ArrayList<>();
String sql = "SELECT * FROM food_info WHERE category_id = ? AND status = 1";
// 查询实现细节
return foodList;
}
}

地理位置服务模块通过集成百度地图API实现附近美食搜索功能,该功能基于用户当前位置动态计算距离并排序:
function initMap() {
var map = new BMap.Map("mapContainer");
var geolocation = new BMap.Geolocation();
geolocation.getCurrentPosition(function(r) {
if(this.getStatus() == BMAP_STATUS_SUCCESS) {
var pt = r.point;
map.centerAndZoom(pt, 15);
// 获取附近美食数据
$.getJSON('NearbyFoodServlet?lat=' + pt.lat + '&lng=' + pt.lng, function(data) {
displayNearbyFoods(data, map);
});
}
});
}
function displayNearbyFoods(foods, map) {
foods.forEach(function(food) {
var point = new BMap.Point(food.longitude, food.latitude);
var marker = new BMap.Marker(point);
map.addOverlay(marker);
var infoWindow = new BMap.InfoWindow(`
<div class="food-info-window">
<h4>${food.name}</h4>
<p>距离:${food.distance}米</p>
<p>价格:¥${food.price}</p>
</div>
`);
marker.addEventListener("click", function() {
this.openInfoWindow(infoWindow);
});
});
}

收藏功能模块通过会话管理实现用户个性化数据持久化:
public class FavoriteServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("currentUser");
if(user == null) {
response.getWriter().write("{\"status\":\"error\",\"message\":\"请先登录\"}");
return;
}
int foodId = Integer.parseInt(request.getParameter("foodId"));
String action = request.getParameter("action");
FavoriteDAO favoriteDAO = new FavoriteDAO();
boolean success = false;
if("add".equals(action)) {
success = favoriteDAO.addFavorite(user.getId(), foodId);
} else if("remove".equals(action)) {
success = favoriteDAO.removeFavorite(user.getId(), foodId);
}
String result = success ? "{\"status\":\"success\"}" : "{\"status\":\"error\"}";
response.getWriter().write(result);
}
}
系统采用过滤器技术实现统一的字符编码处理和权限验证:
@WebFilter("/*")
public class EncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
}
@WebFilter("/admin/*")
public class AdminAuthFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
User user = (User) session.getAttribute("currentUser");
if(user == null || !"admin".equals(user.getType())) {
res.sendRedirect(req.getContextPath() + "/login.jsp");
return;
}
chain.doFilter(request, response);
}
}

数据统计模块为管理员提供业务洞察能力:
public class StatisticsDAO {
public Map<String, Object> getDashboardData() {
Map<String, Object> data = new HashMap<>();
String sql = "SELECT " +
"(SELECT COUNT(*) FROM user WHERE type = 'user') as userCount, " +
"(SELECT COUNT(*) FROM restaurant) as restaurantCount, " +
"(SELECT COUNT(*) FROM food_info WHERE status = 1) as foodCount, " +
"(SELECT COUNT(*) FROM favorite) as favoriteCount";
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if(rs.next()) {
data.put("userCount", rs.getInt("userCount"));
data.put("restaurantCount", rs.getInt("restaurantCount"));
data.put("foodCount", rs.getInt("foodCount"));
data.put("favoriteCount", rs.getInt("favoriteCount"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return data;
}
}

在实体模型设计方面,系统通过面向对象的方式封装业务数据:
public class Food {
private int id;
private String name;
private String description;
private BigDecimal price;
private int restaurantId;
private int categoryId;
private String imageUrl;
private int status;
private Timestamp createTime;
private Timestamp updateTime;
// 构造函数、getter和setter方法
public Food() {}
public Food(String name, String description, BigDecimal price,
int restaurantId, int categoryId, String imageUrl) {
this.name = name;
this.description = description;
this.price = price;
this.restaurantId = restaurantId;
this.categoryId = categoryId;
this.imageUrl = imageUrl;
}
// 完整的getter和setter方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// 其他属性方法...
}
数据库连接管理采用连接池技术优化性能:
public class DBUtil {
private static DataSource dataSource;
static {
try {
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
dataSource = (DataSource) envContext.lookup("jdbc/travelFoodDB");
} catch (NamingException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
系统在以下方面具有显著的技术优势:采用标准的MVC架构确保代码的可维护性;通过DAO模式实现数据访问层的抽象;使用过滤器技术处理跨切面关注点;集成第三方地图服务增强用户体验。
未来优化方向包括:引入Redis缓存层提升系统性能,实现Elasticsearch全文搜索提高查询效率,开发微信小程序扩展移动端访问渠道,集成支付功能支持在线预订,以及采用微服务架构提升系统可扩展性。这些优化将进一步提升系统的实用性和技术先进性。