Java打造抖音同款系统:从0到1的技术揭秘

目录

一、系统架构设计

1.1 整体架构概览

1.2 关键组件选型

 二、功能模块实现

2.1 用户模块

2.1.1 用户注册与登录

2.1.2 用户信息管理

2.2 视频模块

2.2.1 视频上传

2.2.2 视频播放

2.2.3 视频推荐

2.3 社交模块

2.3.1 点赞、评论与分享

2.3.2 关注与粉丝

 三、性能优化与安全保障

3.1 性能优化

3.1.1 缓存机制

3.1.2 数据库优化

3.2 安全保障

3.2.1 用户数据加密

3.2.2 防止恶意攻击


一、系统架构设计

 

1.1 整体架构概览

抖音这样的短视频系统,整体架构可采用当下流行的微服务架构 ,将系统拆分为多个独立的、可独立部署和扩展的微服务模块,以此来应对海量用户请求和高并发场景。以下是几个核心的微服务模块及其职责:

  • 用户模块:负责用户的注册、登录、个人信息管理、密码找回等功能。同时,还处理用户的关注、粉丝关系,以及用户隐私设置等社交相关的用户操作。比如,当用户注册时,该模块验证用户输入的信息,将用户数据存储到数据库,并为用户生成唯一标识。
  • 视频模块:承担视频的上传、存储、转码、审核、下架等操作。在视频上传后,对视频进行转码处理,生成不同分辨率和格式的视频版本,以适配不同设备和网络环境。像抖音上的视频能在手机、平板等各种设备流畅播放,就离不开视频模块的转码工作。
  • 社交模块:实现用户之间的互动功能,包括点赞、评论、分享视频,以及用户之间的私信聊天等。当用户对某个视频点赞时,社交模块会记录点赞行为,并实时更新视频的点赞数,同时通知视频发布者。
  • 推荐模块:基于用户的行为数据、兴趣偏好、视频标签等信息,运用机器学习和深度学习算法,为用户推荐个性化的视频内容。例如,通过分析用户的历史观看记录、点赞和评论的视频类型,推荐模块为用户精准推送符合其兴趣的新视频。
  • 搜索模块:提供视频、用户、话题等内容的搜索功能,支持关键词搜索、模糊搜索和热门搜索推荐。当用户在搜索框输入关键词时,搜索模块快速从海量数据中检索相关内容,并按照相关性和热度进行排序展示。

这些微服务模块之间通过轻量级的通信机制,如 HTTP/RESTful API 或消息队列(如 Kafka)进行通信,实现数据交互和业务流程的协同。例如,当用户发布一个新视频时,视频模块完成视频存储和初步处理后,通过消息队列通知社交模块和推荐模块,社交模块更新相关用户的动态,推荐模块则将新视频纳入推荐候选集。

1.2 关键组件选型

  • 后端框架:选择 Spring Boot 框架,它基于 Spring 框架,遵循 “约定大于配置” 的原则,能极大简化开发过程,提高开发效率。Spring Boot 提供了大量的自动配置,减少了繁琐的 XML 配置文件,使开发者可以更专注于业务逻辑的实现。例如,在配置数据源时,Spring Boot 只需简单的属性配置即可连接到 MySQL 数据库,无需像传统 Spring 项目那样编写大量配置代码。同时,Spring Boot 内置了 Tomcat、Jetty 等 Servlet 容器,可直接以 jar 包形式运行项目,方便部署和运维。
  • 数据库:选用 MySQL 作为主要的关系型数据库,用于存储结构化数据,如用户信息、视频信息、评论信息、点赞信息等。MySQL 具有成熟稳定、性能高效、开源免费、社区支持丰富等优点,能够满足抖音系统对数据存储和复杂查询的需求。以用户信息表为例,可设计包含用户 ID、用户名、密码、手机号、邮箱、注册时间等字段,通过 SQL 语句可以方便地进行用户数据的增删改查操作。同时,为了应对高并发读写场景,可采用分库分表、读写分离等技术对 MySQL 进行优化。
  • 缓存:引入 Redis 作为缓存组件,利用其高性能的内存存储和丰富的数据结构,提高系统的响应速度和并发处理能力。Redis 可以缓存热门视频信息、用户的登录状态、频繁访问的用户数据等。比如,将热门视频的基本信息(如视频 ID、标题、封面图、点赞数等)缓存到 Redis 中,当大量用户请求热门视频列表时,直接从 Redis 中读取数据,减少对 MySQL 数据库的压力,大大提升系统的响应速度。此外,Redis 还支持分布式缓存,可通过集群部署的方式扩展缓存容量和性能。
  • 视频处理:借助 JavaCV 和 FFmpeg 进行视频处理。JavaCV 是一个基于 Java 的计算机视觉库,它封装了 OpenCV 等多个计算机视觉库,提供了丰富的图像和视频处理功能,方便在 Java 代码中进行视频的读取、写入、剪辑、特效添加等操作。FFmpeg 是一个强大的音视频处理工具,支持多种视频格式的编解码、转码、裁剪、合并等操作。在抖音系统中,使用 JavaCV 结合 FFmpeg,可实现视频上传后的格式转换、分辨率调整、视频剪辑、添加水印等功能。例如,将用户上传的各种格式视频统一转码为 MP4 格式,以适配不同平台的播放需求。
  • 视频传输:采用 HTTP/2 协议进行视频传输,HTTP/2 协议相比 HTTP/1.1 协议具有多路复用、头部压缩、服务器推送等特性,能够显著提高视频传输的效率和性能,减少视频加载的延迟,提升用户观看体验。同时,使用 Nginx 服务器作为反向代理和负载均衡器,一方面,Nginx 可以将客户端的请求转发到后端的视频服务器,实现动静分离,提高网站的访问速度;另一方面,通过 Nginx 的负载均衡功能,将视频请求均匀分配到多个后端服务器上,避免单个服务器负载过高,确保系统的高可用性和稳定性。

 二、功能模块实现

2.1 用户模块

2.1.1 用户注册与登录

使用 Spring Boot 实现用户注册和登录功能,首先需要定义用户实体类User,包含用户名、密码、手机号等字段。

public class User {
    private Long id;
    private String username;
    private String password;
    private String phone;
    // 其他字段及getter、setter方法
}

 在注册功能中,需要对用户输入的信息进行验证,确保用户名、密码等必填字段不为空,密码强度符合要求等。例如,使用正则表达式验证密码强度:

import java.util.regex.Pattern;

public class UserRegistrationService {
    private static final Pattern PASSWORD_PATTERN = Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,}$");

    public boolean validatePassword(String password) {
        return PASSWORD_PATTERN.matcher(password).matches();
    }

    public boolean registerUser(User user) {
        if (!validatePassword(user.getPassword())) {
            return false;
        }
        // 此处省略保存用户到数据库的逻辑,假设使用JPA
        userRepository.save(user);
        return true;
    }
}

 在登录功能中,需要根据用户输入的用户名或手机号查询数据库,验证密码是否正确。以下是使用 Spring Security 进行登录验证的示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

@Service
public class UserLoginService {
    @Autowired
    private AuthenticationManager authenticationManager;

    public boolean login(String username, String password) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(username, password));
        if (authentication.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authentication);
            return true;
        }
        return false;
    }
}

 

2.1.2 用户信息管理

用户信息修改功能可通过 MyBatis 操作数据库实现。首先定义UserMapper接口:

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;

@Mapper
public interface UserMapper {
    @Update("UPDATE user SET username = #{username}, phone = #{phone} WHERE id = #{id}")
    int updateUser(User user);
}

 在业务层调用UserMapper的updateUser方法来实现用户信息修改:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoService {
    @Autowired
    private UserMapper userMapper;

    public boolean updateUserInfo(User user) {
        return userMapper.updateUser(user) > 0;
    }
}

 用户信息查询功能同样可以通过 MyBatis 实现。例如,根据用户 ID 查询用户信息:

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")
    User getUserById(Long id);
}

 在业务层调用UserMapper的getUserById方法获取用户信息:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoService {
    @Autowired
    private UserMapper userMapper;

    public User getUserInfo(Long id) {
        return userMapper.getUserById(id);
    }
}

 

2.2 视频模块

2.2.1 视频上传

使用 Java 实现视频上传,可借助 Spring Boot 的MultipartFile来处理文件上传。首先在控制器中接收上传的视频文件:

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

@RestController
public class VideoUploadController {
    private static final String UPLOAD_DIR = "uploads/videos/";

    @PostMapping("/uploadVideo")
    public String uploadVideo(@RequestParam("video") MultipartFile videoFile) {
        try {
            String originalFileName = videoFile.getOriginalFilename();
            String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
            String uniqueFileName = UUID.randomUUID().toString() + fileExtension;
            Path filePath = Paths.get(UPLOAD_DIR + uniqueFileName);
            Files.write(filePath, videoFile.getBytes());
            // 保存文件路径到数据库,假设使用JPA
            Video video = new Video();
            video.setFilePath(UPLOAD_DIR + uniqueFileName);
            videoRepository.save(video);
            return "Video uploaded successfully";
        } catch (IOException e) {
            e.printStackTrace();
            return "Video upload failed";
        }
    }
}

 

2.2.2 视频播放

视频播放功能实现涉及视频流处理和格式转换。在 Java 中,可调用 FFmpeg 实现视频格式转换。以下是一个简单的 Java 代码示例,用于将上传的视频转换为 MP4 格式:

 

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class VideoTranscoding {
    private static final String FFMPEG_PATH = "ffmpeg"; // 假设ffmpeg已配置环境变量

    public static void convertToMp4(String inputFilePath, String outputFilePath) {
        List<String> command = new ArrayList<>();
        command.add(FFMPEG_PATH);
        command.add("-i");
        command.add(inputFilePath);
        command.add("-c:v");
        command.add("libx264");
        command.add("-preset");
        command.add("ultrafast");
        command.add("-profile:v");
        command.add("baseline");
        command.add("-c:a");
        command.add("aac");
        command.add("-strict");
        command.add("experimental");
        command.add(outputFilePath);

        try {
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            Process process = processBuilder.start();
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 在视频播放时,可通过 HTTP 协议将视频文件流传输给客户端。例如,使用 Spring Boot 的ResponseBody将视频文件以流的形式返回:

import org.springframework.core.io.FileSystemResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;

@RestController
public class VideoPlayController {
    @GetMapping("/playVideo/{videoId}")
    public ResponseEntity<FileSystemResource> playVideo(@PathVariable Long videoId) {
        // 根据videoId从数据库获取视频文件路径
        String videoFilePath = videoRepository.findById(videoId).get().getFilePath();
        File videoFile = new File(videoFilePath);
        return ResponseEntity.ok()
              .contentType(MediaType.parseMediaType("video/mp4"))
              .body(new FileSystemResource(videoFile));
    }
}

 

2.2.3 视频推荐

基于用户行为数据和机器学习算法实现个性化视频推荐功能。算法原理主要是通过分析用户的历史观看记录、点赞、评论、收藏等行为数据,构建用户兴趣画像。例如,使用协同过滤算法,寻找具有相似兴趣爱好的用户群体,将这些用户喜欢的视频推荐给目标用户;或者使用内容过滤算法,根据视频的标签、类别、主题等内容特征,推荐与用户历史观看视频内容相似的视频。

实现思路上,首先需要收集和存储用户行为数据到数据库中。然后定期对这些数据进行分析和处理,训练机器学习模型。在用户请求视频推荐时,调用训练好的模型,根据用户的 ID 或当前行为,计算出推荐视频列表,并返回给用户。具体实现中,可使用 Apache Mahout、Spark MLlib 等机器学习库来辅助实现推荐算法 。例如,使用 Mahout 的协同过滤算法实现视频推荐:

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.UserBasedRecommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

import java.io.File;
import java.util.List;

public class VideoRecommendation {
    public static List<RecommendedItem> recommendVideos(long userId, int numRecommendations) throws TasteException {
        DataModel model = new FileDataModel(new File("user_behavior_data.csv"));
        UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(10, similarity, model);
        UserBasedRecommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);
        return recommender.recommend(userId, numRecommendations);
    }
}

 

2.3 社交模块

2.3.1 点赞、评论与分享

点赞和评论功能实现首先需要设计数据库表。以点赞表为例,可包含点赞 ID、用户 ID、视频 ID、点赞时间等字段;评论表可包含评论 ID、用户 ID、视频 ID、评论内容、评论时间等字段。

在业务逻辑处理上,点赞功能实现代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LikeService {
    @Autowired
    private LikeMapper likeMapper;

    public boolean likeVideo(Long userId, Long videoId) {
        Like like = new Like();
        like.setUserId(userId);
        like.setVideoId(videoId);
        like.setLikeTime(System.currentTimeMillis());
        return likeMapper.insertLike(like) > 0;
    }

    public boolean unlikeVideo(Long userId, Long videoId) {
        return likeMapper.deleteLike(userId, videoId) > 0;
    }
}

 评论功能实现代码类似:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CommentService {
    @Autowired
    private CommentMapper commentMapper;

    public boolean addComment(Comment comment) {
        comment.setCommentTime(System.currentTimeMillis());
        return commentMapper.insertComment(comment) > 0;
    }

    public List<Comment> getCommentsByVideoId(Long videoId) {
        return commentMapper.selectCommentsByVideoId(videoId);
    }
}

 分享功能实现可通过调用第三方分享接口,如微信分享、QQ 分享等。以微信分享为例,可使用微信开放平台提供的 SDK,在前端页面中调用微信分享 API,将视频链接、标题、描述等信息传递给微信客户端,实现视频分享:

 

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>视频分享</title>
    <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
    <script>
        wx.config({
            debug: false,
            appId: 'your_app_id',
            timestamp: 'your_timestamp',
            nonceStr: 'your_nonce_str',
            signature: 'your_signature',
            jsApiList: ['onMenuShareAppMessage']
        });
        wx.ready(function () {
            wx.onMenuShareAppMessage({
                title: '精彩视频分享',
                desc: '快来观看这个有趣的视频',
                link: 'https://your_video_url',
                imgUrl: 'https://your_video_cover_url',
                success: function () {
                    alert('分享成功');
                },
                cancel: function () {
                    alert('分享取消');
                }
            });
        });
    </script>
</head>
<body>
</body>
</html>
2.3.2 关注与粉丝

关注和粉丝功能实现需要设计关注表,包含关注 ID、关注者 ID、被关注者 ID、关注时间等字段。关注操作数据库代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class FollowService {
    @Autowired
    private FollowMapper followMapper;

    public boolean followUser(Long followerId, Long followeeId) {
        Follow follow = new Follow();
        follow.setFollowerId(followerId);
        follow.setFolloweeId(followeeId);
        follow.setFollowTime(System.currentTimeMillis());
        return followMapper.insertFollow(follow) > 0;
    }

    public boolean unfollowUser(Long followerId, Long followeeId) {
        return followMapper.deleteFollow(followerId, followeeId) > 0;
    }
}

 粉丝列表获取实现可通过查询关注表,根据被关注者 ID 查询所有关注者信息:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class FollowService {
    @Autowired
    private FollowMapper followMapper;

    public List<User> getFollowers(Long followeeId) {
        return followMapper.selectFollowersByFolloweeId(followeeId);
    }
}

 三、性能优化与安全保障

3.1 性能优化

3.1.1 缓存机制

为了提高系统响应速度,减少数据库的压力,我们引入 Redis 作为缓存组件。Redis 是一种高性能的内存数据库,能够快速存储和读取数据。在抖音系统中,我们可以使用 Redis 缓存热门视频、用户信息、点赞数、评论数等频繁访问的数据。

以下是使用 Jedis 库操作 Redis 缓存热门视频的代码示例:

import redis.clients.jedis.Jedis;

public class VideoCache {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;

    public static void setVideoToCache(String videoId, String videoInfo) {
        try (Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT)) {
            jedis.setex("video:" + videoId, 3600, videoInfo); // 缓存1小时
        }
    }

    public static String getVideoFromCache(String videoId) {
        try (Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT)) {
            return jedis.get("video:" + videoId);
        }
    }
}

在上述代码中,setVideoToCache方法将视频信息存入 Redis 缓存,设置过期时间为 1 小时;getVideoFromCache方法从 Redis 缓存中获取视频信息。当用户请求热门视频时,首先从 Redis 缓存中获取,如果缓存中不存在,则从数据库中查询,然后将查询结果存入缓存,以便下次快速访问。

3.1.2 数据库优化

数据库优化是提高系统性能的关键环节,以下是几种常见的数据库优化措施:

  • 索引优化:在数据库表的常用查询字段上创建索引,可以大大提高查询效率。例如,在用户表的username字段上创建索引:

 CREATE INDEX idx_username ON user (username);

 在 Java 中,使用 JPA(Java Persistence API)可以在实体类上定义索引:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity
@Table(name = "user", indexes = {
    @Index(name = "idx_username", columnList = "username")
})
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    // 其他字段及getter、setter方法
}

 

  • 分页查询优化:在实现分页功能时,传统的limit offset, limit方式在查询偏移量较大的数据时性能较低。以 MySQL 数据库为例,当查询大表中靠后的数据时,如select * from video limit 10000, 10,会先读取 10010 条记录,然后抛弃前 10000 条,效率低下。可采用根据自增主键优化的方式,若主键自增且连续,原查询可改写为select * from video where id > 10000 limit 10,这样走索引且扫描行数大大减少,效率更高。但该方法要求主键自增连续且结果按主键排序。若按非主键字段排序分页,如select * from video ORDER BY title limit 90000, 5,因扫描索引找无索引行成本高,优化器可能放弃索引。此时可利用覆盖索引优化,先查主键再关联查记录,如select * from video v inner join (select id from video order by title limit 90000, 5) vi on v.id = vi.id,查询和排序在覆盖索引树上进行,效率大幅提升。
  • 连接池使用:使用数据库连接池可以复用数据库连接,减少连接的建立和关闭开销,提高系统性能。HikariCP 是一个高性能的 JDBC 连接池,在 Spring Boot 项目中使用 HikariCP 作为连接池的配置示例如下:

 

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource(
        @Value("${spring.datasource.url}") String url,
        @Value("${spring.datasource.username}") String username,
        @Value("${spring.datasource.password}") String password
    ) {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(url);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(10); // 设置最大连接数
        return new HikariDataSource(config);
    }
}

 

通过上述优化措施,系统在处理大量数据和高并发请求时,性能得到显著提升。例如,在进行复杂查询时,优化前可能需要数秒才能返回结果,优化后通过索引优化和合理的查询语句调整,响应时间缩短至几百毫秒;在高并发场景下,使用连接池复用连接,系统能够更快地处理用户请求,吞吐量大幅提高 ,极大提升了用户体验。

3.2 安全保障

3.2.1 用户数据加密

在用户数据安全方面,我们采取了以下措施:

  • 密码加密存储:使用 BCrypt 算法对用户密码进行加密存储,该算法使用了随机生成的盐,使得每次哈希的结果都不同,并且哈希计算非常耗时,增加了破解密码的难度。示例代码如下
import org.mindrot.jbcrypt.BCrypt;

public class PasswordUtil {
    public static String hashPassword(String plainPassword) {
        return BCrypt.hashpw(plainPassword, BCrypt.gensalt());
    }

    public static boolean verifyPassword(String plainPassword, String hashedPassword) {
        return BCrypt.checkpw(plainPassword, hashedPassword);
    }
}

在用户注册时,调用hashPassword方法对用户输入的密码进行加密,然后将加密后的密码存储到数据库中;在用户登录时,调用verifyPassword方法验证用户输入的密码与数据库中存储的加密密码是否匹配。

  • 数据传输加密:使用 HTTPS 协议加密数据传输,确保用户数据在网络传输过程中的安全性。在 Spring Boot 项目中,可以通过配置 Tomcat 的 SSL 连接器来启用 HTTPS。首先,需要准备 SSL 证书,假设证书文件为keystore.jks,密码为password,在application.properties文件中添加如下配置:
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=password
server.ssl.key-password=password
server.ssl.protocol=TLS

 

上述配置告诉 Spring Boot 应用程序使用指定的密钥库文件和密码来启用 HTTPS 协议,确保数据在传输过程中被加密,防止数据被窃取或篡改。

3.2.2 防止恶意攻击

为了防止恶意攻击,我们采取了以下措施:

  • 防止 SQL 注入:使用预编译语句(PreparedStatement)来执行 SQL 查询,将 SQL 语句与数据分离,避免用户输入的数据被当作 SQL 代码执行。例如,在查询用户信息时,使用预编译语句的示例代码如下:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserQuery {
    public static User getUserById(Long userId) {
        String sql = "SELECT * FROM user WHERE id =?";
        try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
             PreparedStatement statement = connection.prepareStatement(sql)) {
            statement.setLong(1, userId);
            try (ResultSet resultSet = statement.executeQuery()) {
                if (resultSet.next()) {
                    User user = new User();
                    user.setId(resultSet.getLong("id"));
                    user.setUsername(resultSet.getString("username"));
                    // 设置其他字段
                    return user;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

 

在上述代码中,?是占位符,用户输入的userId作为参数传递给预编译语句,而不是直接拼接到 SQL 字符串中,从而有效防止了 SQL 注入攻击。

  • 防止 XSS 攻击:对用户输入进行过滤和转义,避免恶意脚本注入。使用 Apache Commons Text 库的StringEscapeUtils类对用户输入进行 HTML 转义,示例代码如下:
import org.apache.commons.text.StringEscapeUtils;

public class XssProtection {
    public static String escapeHtml(String input) {
        return StringEscapeUtils.escapeHtml4(input);
    }
}

 在将用户输入的数据展示到前端页面之前,调用escapeHtml方法对数据进行转义,将特殊字符转换为 HTML 实体,防止恶意脚本在浏览器中执行。例如,当用户发表评论时,对评论内容进行转义后再存储到数据库,并在展示评论时保持转义后的状态,确保页面的安全性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值