Java+MySQL实现简易电影推荐系统 入门练习项目

我来帮你创建一个基于Java+MySQL的简易电影推荐系统入门项目。这个项目包含用户管理、电影管理、评分系统和简单的推荐算法。

1. 数据库设计

首先创建数据库和表结构:

-- 创建数据库
CREATE DATABASE movie_recommendation;
USE movie_recommendation;

-- 用户表
CREATE TABLE users (
    user_id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 电影表
CREATE TABLE movies (
    movie_id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(200) NOT NULL,
    genre VARCHAR(100),
    release_year INT,
    director VARCHAR(100),
    description TEXT,
    avg_rating DECIMAL(3,2) DEFAULT 0.0,
    rating_count INT DEFAULT 0
);

-- 评分表
CREATE TABLE ratings (
    rating_id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    movie_id INT NOT NULL,
    rating DECIMAL(2,1) NOT NULL CHECK (rating >= 1.0 AND rating <= 5.0),
    rated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(user_id) ON DELETE CASCADE,
    FOREIGN KEY (movie_id) REFERENCES movies(movie_id) ON DELETE CASCADE,
    UNIQUE KEY unique_user_movie (user_id, movie_id)
);

-- 插入示例数据
INSERT INTO movies (title, genre, release_year, director, description) VALUES
('肖申克的救赎', '剧情', 1994, '弗兰克·德拉邦特', '希望让人自由'),
('霸王别姬', '剧情', 1993, '陈凯歌', '中国电影的巅峰之作'),
('阿甘正传', '剧情', 1994, '罗伯特·泽米吉斯', '生活就像一盒巧克力'),
('泰坦尼克号', '爱情', 1997, '詹姆斯·卡梅隆', '永恒的爱情故事'),
('这个杀手不太冷', '动作', 1994, '吕克·贝松', '大叔与萝莉的温情故事'),
('美丽人生', '剧情', 1997, '罗伯托·贝尼尼', '父爱的伟大'),
('千与千寻', '动画', 2001, '宫崎骏', '奇幻的冒险之旅'),
('辛德勒的名单', '历史', 1993, '史蒂文·斯皮尔伯格', '人性的光辉');

INSERT INTO users (username, email, password) VALUES
('alice', 'alice@example.com', '123456'),
('bob', 'bob@example.com', '123456'),
('charlie', 'charlie@example.com', '123456');

2. Java项目结构

MovieRecommendation/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/movierecommender/
│   │   │       ├── Main.java
│   │   │       ├── model/
│   │   │       │   ├── User.java
│   │   │       │   ├── Movie.java
│   │   │       │   └── Rating.java
│   │   │       ├── dao/
│   │   │       │   ├── DatabaseConnection.java
│   │   │       │   ├── UserDAO.java
│   │   │       │   ├── MovieDAO.java
│   │   │       │   └── RatingDAO.java
│   │   │       ├── service/
│   │   │       │   ├── UserService.java
│   │   │       │   ├── MovieService.java
│   │   │       │   └── RecommendationService.java
│   │   │       └── util/
│   │   │           └── InputUtil.java
│   │   └── resources/
│   └── test/
└── lib/ (MySQL JDBC驱动)

3. 核心代码实现

数据库连接类

// src/main/java/com/movierecommender/dao/DatabaseConnection.java
package com.movierecommender.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnection {
    private static final String URL = "jdbc:mysql://localhost:3306/movie_recommendation?useSSL=false&serverTimezone=UTC";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "your_password"; // 修改为你的MySQL密码
    
    public static Connection getConnection() throws SQLException {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            throw new SQLException("MySQL Driver not found", e);
        }
        return DriverManager.getConnection(URL, USERNAME, PASSWORD);
    }
}

实体类

// src/main/java/com/movierecommender/model/User.java
package com.movierecommender.model;

import java.time.LocalDateTime;

public class User {
    private int userId;
    private String username;
    private String email;
    private String password;
    private LocalDateTime createdAt;
    
    // 构造方法
    public User() {}
    
    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }
    
    // getter和setter方法
    public int getUserId() { return userId; }
    public void setUserId(int userId) { this.userId = userId; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
    public LocalDateTime getCreatedAt() { return createdAt; }
    public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
    
    @Override
    public String toString() {
        return "User{id=" + userId + ", username='" + username + "', email='" + email + "'}";
    }
}
// src/main/java/com/movierecommender/model/Movie.java
package com.movierecommender.model;

import java.time.LocalDate;

public class Movie {
    private int movieId;
    private String title;
    private String genre;
    private Integer releaseYear;
    private String director;
    private String description;
    private Double avgRating;
    private Integer ratingCount;
    
    // 构造方法
    public Movie() {}
    
    public Movie(String title, String genre, Integer releaseYear, String director, String description) {
        this.title = title;
        this.genre = genre;
        this.releaseYear = releaseYear;
        this.director = director;
        this.description = description;
    }
    
    // getter和setter方法
    public int getMovieId() { return movieId; }
    public void setMovieId(int movieId) { this.movieId = movieId; }
    
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    public String getGenre() { return genre; }
    public void setGenre(String genre) { this.genre = genre; }
    
    public Integer getReleaseYear() { return releaseYear; }
    public void setReleaseYear(Integer releaseYear) { this.releaseYear = releaseYear; }
    
    public String getDirector() { return director; }
    public void setDirector(String director) { this.director = director; }
    
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    
    public Double getAvgRating() { return avgRating; }
    public void setAvgRating(Double avgRating) { this.avgRating = avgRating; }
    
    public Integer getRatingCount() { return ratingCount; }
    public void setRatingCount(Integer ratingCount) { this.ratingCount = ratingCount; }
    
    @Override
    public String toString() {
        return String.format("《%s》(%d) - %s\n导演: %s\n类型: %s\n评分: %.1f (%d人评价)\n简介: %s",
                title, releaseYear, genre, director, genre, 
                avgRating != null ? avgRating : 0.0, 
                ratingCount != null ? ratingCount : 0, 
                description);
    }
}
// src/main/java/com/movierecommender/model/Rating.java
package com.movierecommender.model;

import java.time.LocalDateTime;

public class Rating {
    private int ratingId;
    private int userId;
    private int movieId;
    private double rating;
    private LocalDateTime ratedAt;
    
    // 构造方法
    public Rating() {}
    
    public Rating(int userId, int movieId, double rating) {
        this.userId = userId;
        this.movieId = movieId;
        this.rating = rating;
    }
    
    // getter和setter方法
    public int getRatingId() { return ratingId; }
    public void setRatingId(int ratingId) { this.ratingId = ratingId; }
    
    public int getUserId() { return userId; }
    public void setUserId(int userId) { this.userId = userId; }
    
    public int getMovieId() { return movieId; }
    public void setMovieId(int movieId) { this.movieId = movieId; }
    
    public double getRating() { return rating; }
    public void setRating(double rating) { this.rating = rating; }
    
    public LocalDateTime getRatedAt() { return ratedAt; }
    public void setRatedAt(LocalDateTime ratedAt) { this.ratedAt = ratedAt; }
}

DAO层

// src/main/java/com/movierecommender/dao/UserDAO.java
package com.movierecommender.dao;

import com.movierecommender.model.User;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class UserDAO {
    
    public boolean addUser(User user) {
        String sql = "INSERT INTO users (username, email, password) VALUES (?, ?, ?)";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, user.getUsername());
            pstmt.setString(2, user.getEmail());
            pstmt.setString(3, user.getPassword());
            
            int rowsAffected = pstmt.executeUpdate();
            return rowsAffected > 0;
            
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }
    
    public User getUserByUsername(String username) {
        String sql = "SELECT * FROM users WHERE username = ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, username);
            ResultSet rs = pstmt.executeQuery();
            
            if (rs.next()) {
                User user = new User();
                user.setUserId(rs.getInt("user_id"));
                user.setUsername(rs.getString("username"));
                user.setEmail(rs.getString("email"));
                user.setPassword(rs.getString("password"));
                user.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
                return user;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    public List<User> getAllUsers() {
        List<User> users = new ArrayList<>();
        String sql = "SELECT * FROM users";
        
        try (Connection conn = DatabaseConnection.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            
            while (rs.next()) {
                User user = new User();
                user.setUserId(rs.getInt("user_id"));
                user.setUsername(rs.getString("username"));
                user.setEmail(rs.getString("email"));
                user.setCreatedAt(rs.getTimestamp("created_at").toLocalDateTime());
                users.add(user);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return users;
    }
}
// src/main/java/com/movierecommender/dao/MovieDAO.java
package com.movierecommender.dao;

import com.movierecommender.model.Movie;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class MovieDAO {
    
    public List<Movie> getAllMovies() {
        List<Movie> movies = new ArrayList<>();
        String sql = "SELECT * FROM movies ORDER BY movie_id";
        
        try (Connection conn = DatabaseConnection.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            
            while (rs.next()) {
                Movie movie = mapResultSetToMovie(rs);
                movies.add(movie);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return movies;
    }
    
    public Movie getMovieById(int movieId) {
        String sql = "SELECT * FROM movies WHERE movie_id = ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, movieId);
            ResultSet rs = pstmt.executeQuery();
            
            if (rs.next()) {
                return mapResultSetToMovie(rs);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    public List<Movie> getTopRatedMovies(int limit) {
        List<Movie> movies = new ArrayList<>();
        String sql = "SELECT * FROM movies WHERE rating_count > 0 ORDER BY avg_rating DESC LIMIT ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, limit);
            ResultSet rs = pstmt.executeQuery();
            
            while (rs.next()) {
                movies.add(mapResultSetToMovie(rs));
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return movies;
    }
    
    public List<Movie> getMoviesByGenre(String genre) {
        List<Movie> movies = new ArrayList<>();
        String sql = "SELECT * FROM movies WHERE genre LIKE ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setString(1, "%" + genre + "%");
            ResultSet rs = pstmt.executeQuery();
            
            while (rs.next()) {
                movies.add(mapResultSetToMovie(rs));
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return movies;
    }
    
    private Movie mapResultSetToMovie(ResultSet rs) throws SQLException {
        Movie movie = new Movie();
        movie.setMovieId(rs.getInt("movie_id"));
        movie.setTitle(rs.getString("title"));
        movie.setGenre(rs.getString("genre"));
        movie.setReleaseYear(rs.getInt("release_year"));
        movie.setDirector(rs.getString("director"));
        movie.setDescription(rs.getString("description"));
        movie.setAvgRating(rs.getDouble("avg_rating"));
        movie.setRatingCount(rs.getInt("rating_count"));
        return movie;
    }
}
// src/main/java/com/movierecommender/dao/RatingDAO.java
package com.movierecommender.dao;

import com.movierecommender.model.Rating;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class RatingDAO {
    
    public boolean addOrUpdateRating(Rating rating) {
        // 先检查是否已存在评分
        Rating existing = getRating(rating.getUserId(), rating.getMovieId());
        
        if (existing != null) {
            return updateRating(rating);
        } else {
            return addRating(rating);
        }
    }
    
    private boolean addRating(Rating rating) {
        String sql = "INSERT INTO ratings (user_id, movie_id, rating) VALUES (?, ?, ?)";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, rating.getUserId());
            pstmt.setInt(2, rating.getMovieId());
            pstmt.setDouble(3, rating.getRating());
            
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                updateMovieAverageRating(rating.getMovieId());
                return true;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return false;
    }
    
    private boolean updateRating(Rating rating) {
        String sql = "UPDATE ratings SET rating = ? WHERE user_id = ? AND movie_id = ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setDouble(1, rating.getRating());
            pstmt.setInt(2, rating.getUserId());
            pstmt.setInt(3, rating.getMovieId());
            
            int rowsAffected = pstmt.executeUpdate();
            if (rowsAffected > 0) {
                updateMovieAverageRating(rating.getMovieId());
                return true;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return false;
    }
    
    public Rating getRating(int userId, int movieId) {
        String sql = "SELECT * FROM ratings WHERE user_id = ? AND movie_id = ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, userId);
            pstmt.setInt(2, movieId);
            ResultSet rs = pstmt.executeQuery();
            
            if (rs.next()) {
                Rating rating = new Rating();
                rating.setRatingId(rs.getInt("rating_id"));
                rating.setUserId(rs.getInt("user_id"));
                rating.setMovieId(rs.getInt("movie_id"));
                rating.setRating(rs.getDouble("rating"));
                rating.setRatedAt(rs.getTimestamp("rated_at").toLocalDateTime());
                return rating;
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return null;
    }
    
    public List<Rating> getUserRatings(int userId) {
        List<Rating> ratings = new ArrayList<>();
        String sql = "SELECT * FROM ratings WHERE user_id = ? ORDER BY rated_at DESC";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, userId);
            ResultSet rs = pstmt.executeQuery();
            
            while (rs.next()) {
                Rating rating = new Rating();
                rating.setRatingId(rs.getInt("rating_id"));
                rating.setUserId(rs.getInt("user_id"));
                rating.setMovieId(rs.getInt("movie_id"));
                rating.setRating(rs.getDouble("rating"));
                rating.setRatedAt(rs.getTimestamp("rated_at").toLocalDateTime());
                ratings.add(rating);
            }
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        
        return ratings;
    }
    
    private void updateMovieAverageRating(int movieId) {
        String sql = "UPDATE movies SET avg_rating = (SELECT AVG(rating) FROM ratings WHERE movie_id = ?), " +
                    "rating_count = (SELECT COUNT(*) FROM ratings WHERE movie_id = ?) " +
                    "WHERE movie_id = ?";
        
        try (Connection conn = DatabaseConnection.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            
            pstmt.setInt(1, movieId);
            pstmt.setInt(2, movieId);
            pstmt.setInt(3, movieId);
            pstmt.executeUpdate();
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Service层

// src/main/java/com/movierecommender/service/UserService.java
package com.movierecommender.service;

import com.movierecommender.dao.UserDAO;
import com.movierecommender.model.User;
import java.util.List;

public class UserService {
    private UserDAO userDAO = new UserDAO();
    
    public boolean registerUser(String username, String email, String password) {
        if (userDAO.getUserByUsername(username) != null) {
            return false; // 用户名已存在
        }
        
        User user = new User(username, email, password);
        return userDAO.addUser(user);
    }
    
    public User loginUser(String username, String password) {
        User user = userDAO.getUserByUsername(username);
        if (user != null && user.getPassword().equals(password)) {
            return user;
        }
        return null;
    }
    
    public List<User> getAllUsers() {
        return userDAO.getAllUsers();
    }
}
// src/main/java/com/movierecommender/service/MovieService.java
package com.movierecommender.service;

import com.movierecommender.dao.MovieDAO;
import com.movierecommender.model.Movie;
import java.util.List;

public class MovieService {
    private MovieDAO movieDAO = new MovieDAO();
    
    public List<Movie> getAllMovies() {
        return movieDAO.getAllMovies();
    }
    
    public Movie getMovieById(int movieId) {
        return movieDAO.getMovieById(movieId);
    }
    
    public List<Movie> getTopRatedMovies(int limit) {
        return movieDAO.getTopRatedMovies(limit);
    }
    
    public List<Movie> getMoviesByGenre(String genre) {
        return movieDAO.getMoviesByGenre(genre);
    }
}
// src/main/java/com/movierecommender/service/RecommendationService.java
package com.movierecommender.service;

import com.movierecommender.dao.MovieDAO;
import com.movierecommender.dao.RatingDAO;
import com.movierecommender.model.Movie;
import com.movierecommender.model.Rating;
import java.util.*;

public class RecommendationService {
    private MovieDAO movieDAO = new MovieDAO();
    private RatingDAO ratingDAO = new RatingDAO();
    
    // 基于内容的推荐:推荐同类型的电影
    public List<Movie> recommendByGenre(int userId, int limit) {
        List<Rating> userRatings = ratingDAO.getUserRatings(userId);
        Set<String> preferredGenres = new HashSet<>();
        
        // 获取用户评分过的电影的类型
        for (Rating rating : userRatings) {
            Movie movie = movieDAO.getMovieById(rating.getMovieId());
            if (movie != null && rating.getRating() >= 4.0) { // 高评分电影的类型作为偏好
                String[] genres = movie.getGenre().split(",");
                for (String genre : genres) {
                    preferredGenres.add(genre.trim());
                }
            }
        }
        
        // 推荐同类型但用户未看过的电影
        List<Movie> recommendations = new ArrayList<>();
        List<Movie> allMovies = movieDAO.getAllMovies();
        Set<Integer> watchedMovieIds = new HashSet<>();
        
        for (Rating rating : userRatings) {
            watchedMovieIds.add(rating.getMovieId());
        }
        
        for (String genre : preferredGenres) {
            List<Movie> genreMovies = movieDAO.getMoviesByGenre(genre);
            for (Movie movie : genreMovies) {
                if (!watchedMovieIds.contains(movie.getMovieId()) && 
                    !recommendations.contains(movie) && 
                    movie.getRatingCount() > 0) {
                    recommendations.add(movie);
                    if (recommendations.size() >= limit) break;
                }
            }
            if (recommendations.size() >= limit) break;
        }
        
        return recommendations.subList(0, Math.min(recommendations.size(), limit));
    }
    
    // 基于协同过滤的简单推荐:推荐相似用户喜欢的电影
    public List<Movie> recommendByCollaborativeFiltering(int userId, int limit) {
        // 这里实现一个简化版本:找到评分模式相似的用户
        List<Rating> currentUserRatings = ratingDAO.getUserRatings(userId);
        if (currentUserRatings.isEmpty()) {
            return movieDAO.getTopRatedMovies(limit); // 新用户返回热门电影
        }
        
        Map<Integer, Double> userSimilarity = new HashMap<>();
        List<UserRatingProfile> allProfiles = buildUserProfiles();
        
        UserRatingProfile currentProfile = findUserProfile(userId, allProfiles);
        if (currentProfile == null) {
            return movieDAO.getTopRatedMovies(limit);
        }
        
        // 计算与其他用户的相似度
        for (UserRatingProfile profile : allProfiles) {
            if (profile.getUserId() != userId) {
                double similarity = calculateCosineSimilarity(currentProfile, profile);
                userSimilarity.put(profile.getUserId(), similarity);
            }
        }
        
        // 根据相似度排序,取最相似的几个用户
        List<Map.Entry<Integer, Double>> sortedUsers = new ArrayList<>(userSimilarity.entrySet());
        sortedUsers.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
        
        // 推荐相似用户高评分的电影
        Set<Integer> watchedMovieIds = new HashSet<>();
        for (Rating rating : currentUserRatings) {
            watchedMovieIds.add(rating.getMovieId());
        }
        
        List<Movie> recommendations = new ArrayList<>();
        int similarUsersToConsider = Math.min(3, sortedUsers.size());
        
        for (int i = 0; i < similarUsersToConsider; i++) {
            int similarUserId = sortedUsers.get(i).getKey();
            List<Rating> similarUserRatings = ratingDAO.getUserRatings(similarUserId);
            
            for (Rating rating : similarUserRatings) {
                if (rating.getRating() >= 4.0 && !watchedMovieIds.contains(rating.getMovieId())) {
                    Movie movie = movieDAO.getMovieById(rating.getMovieId());
                    if (movie != null && !recommendations.contains(movie)) {
                        recommendations.add(movie);
                        if (recommendations.size() >= limit) break;
                    }
                }
            }
            if (recommendations.size() >= limit) break;
        }
        
        return recommendations.subList(0, Math.min(recommendations.size(), limit));
    }
    
    // 构建用户评分档案
    private List<UserRatingProfile> buildUserProfiles() {
        List<UserRatingProfile> profiles = new ArrayList<>();
        // 这里需要获取所有有评分的用户,简化实现
        return profiles;
    }
    
    // 查找用户档案
    private UserRatingProfile findUserProfile(int userId, List<UserRatingProfile> profiles) {
        for (UserRatingProfile profile : profiles) {
            if (profile.getUserId() == userId) {
                return profile;
            }
        }
        return null;
    }
    
    // 计算余弦相似度(简化版)
    private double calculateCosineSimilarity(UserRatingProfile profile1, UserRatingProfile profile2) {
        // 简化实现,实际应该比较用户对相同电影的评分
        return Math.random() * 0.5 + 0.3; // 返回随机相似度用于演示
    }
    
    // 内部类:用户评分档案
    private static class UserRatingProfile {
        private int userId;
        private Map<Integer, Double> movieRatings = new HashMap<>();
        
        public UserRatingProfile(int userId) {
            this.userId = userId;
        }
        
        public int getUserId() { return userId; }
        public Map<Integer, Double> getMovieRatings() { return movieRatings; }
    }
}

工具类和主程序

// src/main/java/com/movierecommender/util/InputUtil.java
package com.movierecommender.util;

import java.util.Scanner;

public class InputUtil {
    private static Scanner scanner = new Scanner(System.in);
    
    public static String getStringInput(String prompt) {
        System.out.print(prompt);
        return scanner.nextLine().trim();
    }
    
    public static int getIntInput(String prompt) {
        while (true) {
            try {
                System.out.print(prompt);
                return Integer.parseInt(scanner.nextLine().trim());
            } catch (NumberFormatException e) {
                System.out.println("请输入有效的数字!");
            }
        }
    }
    
    public static double getDoubleInput(String prompt) {
        while (true) {
            try {
                System.out.print(prompt);
                return Double.parseDouble(scanner.nextLine().trim());
            } catch (NumberFormatException e) {
                System.out.println("请输入有效的数字!");
            }
        }
    }
    
    public static int getRatingInput(String prompt) {
        while (true) {
            double rating = getDoubleInput(prompt);
            if (rating >= 1.0 && rating <= 5.0) {
                return (int)(rating * 10); // 转换为整数存储
            }
            System.out.println("评分必须在1.0-5.0之间!");
        }
    }
}
// src/main/java/com/movierecommender/Main.java
package com.movierecommender;

import com.movierecommender.model.User;
import com.movierecommender.model.Movie;
import com.movierecommender.model.Rating;
import com.movierecommender.service.UserService;
import com.movierecommender.service.MovieService;
import com.movierecommender.service.RecommendationService;
import com.movierecommender.util.InputUtil;

import java.util.List;

public class Main {
    private static UserService userService = new UserService();
    private static MovieService movieService = new MovieService();
    private static RecommendationService recommendationService = new RecommendationService();
    private static User currentUser = null;
    
    public static void main(String[] args) {
        System.out.println("=== 欢迎使用电影推荐系统 ===");
        
        while (true) {
            if (currentUser == null) {
                showAuthMenu();
            } else {
                showMainMenu();
            }
        }
    }
    
    private static void showAuthMenu() {
        System.out.println("\n--- 用户认证 ---");
        System.out.println("1. 登录");
        System.out.println("2. 注册");
        System.out.println("3. 退出系统");
        System.out.print("请选择操作: ");
        
        int choice = InputUtil.getIntInput("");
        
        switch (choice) {
            case 1:
                login();
                break;
            case 2:
                register();
                break;
            case 3:
                System.out.println("感谢使用,再见!");
                System.exit(0);
                break;
            default:
                System.out.println("无效选择!");
        }
    }
    
    private static void showMainMenu() {
        System.out.println("\n--- 主菜单 (当前用户: " + currentUser.getUsername() + ") ---");
        System.out.println("1. 浏览所有电影");
        System.out.println("2. 查看电影详情");
        System.out.println("3. 搜索电影");
        System.out.println("4. 为电影评分");
        System.out.println("5. 查看我的评分记录");
        System.out.println("6. 热门电影推荐");
        System.out.println("7. 个性化推荐");
        System.out.println("8. 按类型浏览");
        System.out.println("9. 登出");
        System.out.print("请选择操作: ");
        
        int choice = InputUtil.getIntInput("");
        
        switch (choice) {
            case 1:
                browseAllMovies();
                break;
            case 2:
                viewMovieDetails();
                break;
            case 3:
                searchMovies();
                break;
            case 4:
                rateMovie();
                break;
            case 5:
                viewMyRatings();
                break;
            case 6:
                showTopRatedMovies();
                break;
            case 7:
                showPersonalizedRecommendations();
                break;
            case 8:
                browseByGenre();
                break;
            case 9:
                currentUser = null;
                System.out.println("已成功登出!");
                break;
            default:
                System.out.println("无效选择!");
        }
    }
    
    private static void login() {
        String username = InputUtil.getStringInput("用户名: ");
        String password = InputUtil.getStringInput("密码: ");
        
        currentUser = userService.loginUser(username, password);
        if (currentUser != null) {
            System.out.println("登录成功!");
        } else {
            System.out.println("用户名或密码错误!");
        }
    }
    
    private static void register() {
        String username = InputUtil.getStringInput("用户名: ");
        String email = InputUtil.getStringInput("邮箱: ");
        String password = InputUtil.getStringInput("密码: ");
        
        if (userService.registerUser(username, email, password)) {
            System.out.println("注册成功!请登录。");
        } else {
            System.out.println("注册失败!用户名可能已存在。");
        }
    }
    
    private static void browseAllMovies() {
        List<Movie> movies = movieService.getAllMovies();
        System.out.println("\n--- 所有电影 (" + movies.size() + "部) ---");
        
        for (int i = 0; i < movies.size(); i++) {
            System.out.println((i + 1) + ". 《" + movies.get(i).getTitle() + "》(" + 
                             movies.get(i).getReleaseYear() + ") - " + movies.get(i).getGenre());
        }
    }
    
    private static void viewMovieDetails() {
        List<Movie> movies = movieService.getAllMovies();
        if (movies.isEmpty()) {
            System.out.println("暂无电影数据!");
            return;
        }
        
        System.out.println("\n--- 选择电影查看详情 ---");
        for (int i = 0; i < movies.size(); i++) {
            System.out.println((i + 1) + ". 《" + movies.get(i).getTitle() + "》");
        }
        
        int choice = InputUtil.getIntInput("请选择电影编号: ") - 1;
        if (choice >= 0 && choice < movies.size()) {
            Movie movie = movies.get(choice);
            System.out.println("\n" + movie);
            
            // 显示用户是否评过分
            Rating rating = new com.movierecommender.dao.RatingDAO()
                .getRating(currentUser.getUserId(), movie.getMovieId());
            if (rating != null) {
                System.out.println("您的评分: " + (rating.getRating() / 10.0));
            }
        } else {
            System.out.println("无效选择!");
        }
    }
    
    private static void searchMovies() {
        String keyword = InputUtil.getStringInput("请输入电影名称关键词: ");
        List<Movie> allMovies = movieService.getAllMovies();
        List<Movie> results = new java.util.ArrayList<>();
        
        for (Movie movie : allMovies) {
            if (movie.getTitle().toLowerCase().contains(keyword.toLowerCase()) ||
                movie.getDirector().toLowerCase().contains(keyword.toLowerCase()) ||
                movie.getGenre().toLowerCase().contains(keyword.toLowerCase())) {
                results.add(movie);
            }
        }
        
        if (results.isEmpty()) {
            System.out.println("没有找到相关电影!");
        } else {
            System.out.println("\n--- 搜索结果 (" + results.size() + "部) ---");
            for (int i = 0; i < results.size(); i++) {
                System.out.println((i + 1) + ". 《" + results.get(i).getTitle() + "》(" + 
                                 results.get(i).getReleaseYear() + ") - " + results.get(i).getGenre());
            }
        }
    }
    
    private static void rateMovie() {
        List<Movie> movies = movieService.getAllMovies();
        if (movies.isEmpty()) {
            System.out.println("暂无电影可评分!");
            return;
        }
        
        System.out.println("\n--- 选择要评分的电影 ---");
        for (int i = 0; i < movies.size(); i++) {
            System.out.println((i + 1) + ". 《" + movies.get(i).getTitle() + "》");
        }
        
        int choice = InputUtil.getIntInput("请选择电影编号: ") - 1;
        if (choice < 0 || choice >= movies.size()) {
            System.out.println("无效选择!");
            return;
        }
        
        Movie selectedMovie = movies.get(choice);
        double rating = InputUtil.getDoubleInput("请给《" + selectedMovie.getTitle() + "》评分(1.0-5.0): ");
        
        com.movierecommender.dao.RatingDAO ratingDAO = new com.movierecommender.dao.RatingDAO();
        Rating newRating = new Rating(currentUser.getUserId(), selectedMovie.getMovieId(), rating);
        
        if (ratingDAO.addOrUpdateRating(newRating)) {
            System.out.println("评分成功!");
        } else {
            System.out.println("评分失败!");
        }
    }
    
    private static void viewMyRatings() {
        com.movierecommender.dao.RatingDAO ratingDAO = new com.movierecommender.dao.RatingDAO();
        List<Rating> myRatings = ratingDAO.getUserRatings(currentUser.getUserId());
        
        if (myRatings.isEmpty()) {
            System.out.println("您还没有评分记录!");
            return;
        }
        
        System.out.println("\n--- 我的评分记录 (" + myRatings.size() + "条) ---");
        for (Rating rating : myRatings) {
            Movie movie = movieService.getMovieById(rating.getMovieId());
            if (movie != null) {
                System.out.printf("《%s》 - 评分: %.1f (评分时间: %s)%n", 
                    movie.getTitle(), rating.getRating() / 10.0, rating.getRatedAt());
            }
        }
    }
    
    private static void showTopRatedMovies() {
        int limit = InputUtil.getIntInput("显示前几名热门电影(默认5): ");
        if (limit <= 0) limit = 5;
        
        List<Movie> topMovies = movieService.getTopRatedMovies(limit);
        
        if (topMovies.isEmpty()) {
            System.out.println("暂无评分数据!");
            return;
        }
        
        System.out.println("\n--- 热门电影 TOP " + topMovies.size() + " ---");
        for (int i = 0; i < topMovies.size(); i++) {
            Movie movie = topMovies.get(i);
            System.out.printf("%d. 《%s》(%.1f分) - %s%n", 
                i + 1, movie.getTitle(), movie.getAvgRating(), movie.getGenre());
        }
    }
    
    private static void showPersonalizedRecommendations() {
        System.out.println("\n--- 选择推荐方式 ---");
        System.out.println("1. 基于内容推荐(同类型电影)");
        System.out.println("2. 协同过滤推荐(相似用户喜欢)");
        System.out.print("请选择: ");
        
        int choice = InputUtil.getIntInput("");
        int limit = InputUtil.getIntInput("推荐数量(默认5): ");
        if (limit <= 0) limit = 5;
        
        List<Movie> recommendations;
        
        switch (choice) {
            case 1:
                recommendations = recommendationService.recommendByGenre(currentUser.getUserId(), limit);
                break;
            case 2:
                recommendations = recommendationService.recommendByCollaborativeFiltering(currentUser.getUserId(), limit);
                break;
            default:
                System.out.println("无效选择!");
                return;
        }
        
        if (recommendations.isEmpty()) {
            System.out.println("暂时没有合适的推荐,试试给一些电影评分吧!");
            return;
        }
        
        System.out.println("\n--- 为您推荐 " + recommendations.size() + " 部电影 ---");
        for (int i = 0; i < recommendations.size(); i++) {
            Movie movie = recommendations.get(i);
            System.out.printf("%d. 《%s》(%d) - %s [%.1f分]%n", 
                i + 1, movie.getTitle(), movie.getReleaseYear(), 
                movie.getGenre(), movie.getAvgRating());
        }
    }
    
    private static void browseByGenre() {
        String genre = InputUtil.getStringInput("请输入电影类型(如: 剧情, 动作, 爱情等): ");
        List<Movie> genreMovies = movieService.getMoviesByGenre(genre);
        
        if (genreMovies.isEmpty()) {
            System.out.println("该类型下暂无电影!");
            return;
        }
        
        System.out.println("\n--- " + genre + " 类型电影 (" + genreMovies.size() + "部) ---");
        for (int i = 0; i < genreMovies.size(); i++) {
            Movie movie = genreMovies.get(i);
            System.out.printf("%d. 《%s》(%d) - [%.1f分]%n", 
                i + 1, movie.getTitle(), movie.getReleaseYear(), movie.getAvgRating());
        }
    }
}

4. 项目配置说明

  1. 环境要求

    • JDK 8+

    • MySQL 5.7+ 或 8.0+

    • MySQL Connector/J 驱动

  2. 数据库配置

    • 修改 DatabaseConnection.java中的数据库连接信息

    • 确保MySQL服务运行正常

    • 执行提供的SQL脚本创建数据库和表

  3. 依赖管理

    • 下载MySQL JDBC驱动并添加到classpath

    • 或使用Maven/Gradle管理依赖

5. 功能特点

  • ✅ 用户注册/登录系统

  • ✅ 电影信息管理

  • ✅ 用户评分系统

  • ✅ 基于内容的推荐算法

  • ✅ 简化的协同过滤推荐

  • ✅ 热门电影排行

  • ✅ 按类型浏览

  • ✅ 搜索功能

  • ✅ 评分历史查看

6. 学习要点

  1. Java基础:面向对象编程、集合框架

  2. 数据库操作:JDBC连接、CRUD操作

  3. MVC架构:模型-视图-控制器分离

  4. 推荐算法:内容推荐、协同过滤基础

  5. 系统设计:分层架构、DAO模式

这个项目适合Java初学者学习数据库应用开发和推荐系统基础概念。你可以根据需要扩展更多功能,如更复杂的推荐算法、Web界面等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值