001 定期同步mysql数据到es 删除数据库记录同时删除es记录 es全文搜索分词和高亮

ops/2024/10/19 2:22:56/

文章目录

    • ProductController.java
    • Product.java
    • ElasticsearchSyncListener.java
    • ProductElasticSearchMapper.java
    • ProductMapper.java
    • ProductDeletedEvent.java
    • ProductServiceImpl.java
    • SyncProductService.java
    • IProductService.java
    • ElasticSearchSpringDemoApplication.java
    • ServletInitializer.java
    • product.sql
    • 同步
    • ProductMapper.xml
    • application.yaml
    • pom.xml

ProductController.java


package com.example.controller;import com.example.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;/*** <p>*  前端控制器* </p>** @author dd* @since 2024-05-07**///测试:http://localhost:8080/es_demo/product/kw/纯棉四件套/page/1
@RestController
@RequestMapping("product")
public class ProductController {@Autowiredprivate IProductService productService;// 将mysql中的product数据保存到es中@GetMapping("saveProductToES")public String saveProductToES(){productService.saveProductFromDBToES();return "ok";}//在生产环境中,直接操作Elasticsearch通常需要更复杂的错误处理和事务管理逻辑,以确保数据的一致性和完整性。@GetMapping("delete/{productId}")public String deleteProduct(@PathVariable Integer productId){return productService.deleteProduct(productId);}// 搜索引擎:输入关键字//返回 商品信息 + 页码信息@GetMapping("kw/{kw}/page/{pageNum}")public Map<String, Object> getByKeyword(@PathVariable("kw") String keyword,@PathVariable("pageNum") Integer pageNum){if(pageNum == null)pageNum = 1;Map<String, Object> result = productService.getByNameAndInfo(keyword, keyword, pageNum);return result;}}

Product.java


package com.example.entity;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** <p>* * </p>** @author dd* @since 2024-05-07*///    @Field(index = false, store = true,
//            type = FieldType.Date,format = DateFormat.custom,
//            pattern = "yyyy-MM-dd HH:mm:ss")@Document(indexName = "myproduct")
public class Product implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "product_id",type = IdType.AUTO)@Idprivate Integer productId;@Field(type = FieldType.Keyword)private String productName;private BigDecimal productPrice;private String productImg;private Integer productCount;@Field( type = FieldType.Date,name = "update_time",format = {},pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00' || strict_date_opotional_time || epoch_millis")private LocalDateTime createTime;@Field( type = FieldType.Date,name = "update_time",format = {},pattern = "yyyy-MM-dd HH:mm:ss || yyyy-MM-dd'T'HH:mm:ss'+08:00' || strict_date_opotional_time || epoch_millis")private LocalDateTime updateTime;@Field(type = FieldType.Text,analyzer = "ik_smart",searchAnalyzer = "ik_max_word")private String productInfo;public Integer getProductId() {return productId;}public void setProductId(Integer productId) {this.productId = productId;}public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}public BigDecimal getProductPrice() {return productPrice;}public void setProductPrice(BigDecimal productPrice) {this.productPrice = productPrice;}public String getProductImg() {return productImg;}public void setProductImg(String productImg) {this.productImg = productImg;}public Integer getProductCount() {return productCount;}public void setProductCount(Integer productCount) {this.productCount = productCount;}public LocalDateTime getCreateTime() {return createTime;}public void setCreateTime(LocalDateTime createTime) {this.createTime = createTime;}public LocalDateTime getUpdateTime() {return updateTime;}public void setUpdateTime(LocalDateTime updateTime) {this.updateTime = updateTime;}public String getProductInfo() {return productInfo;}public void setProductInfo(String productInfo) {this.productInfo = productInfo;}@Overridepublic String toString() {return "Product{" +"productId=" + productId +", productName=" + productName +", productPrice=" + productPrice +", productImg=" + productImg +", productCount=" + productCount +", createTime=" + createTime +", updateTime=" + updateTime +", productInfo=" + productInfo +"}";}
}

ElasticsearchSyncListener.java


package com.example.listener;import com.example.service.impl.ProductDeletedEvent;
import com.example.mapper.ProductElasticSearchMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;@Component
public class ElasticsearchSyncListener {@Autowiredprivate ProductElasticSearchMapper productElasticSearchMapper;@EventListenerpublic void handleProductDeletedEvent(ProductDeletedEvent event) {Integer productId = event.getProductId();// 删除Elasticsearch中的记录productElasticSearchMapper.deleteById(productId);}
}

ProductElasticSearchMapper.java


package com.example.mapper;import com.example.entity.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;import java.util.List;@Repository //父接口已经 实现对象在es中的基础CRUD操作
public interface ProductElasticSearchMapper extends ElasticsearchRepository<Product,Integer> {//方法名必须是:findBy + pojo类属性名(首字母大写)public List<Product> findByProductName(String productName);public List<Product> findByProductInfo(String productInfo);}

ProductMapper.java


package com.example.mapper;import com.example.entity.Product;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;import java.util.List;/*** <p>*  Mapper 接口* </p>** @author dd* @since 2024-05-07*/public interface ProductMapper extends BaseMapper<Product> {}

ProductDeletedEvent.java


package com.example.service.impl;import org.springframework.context.ApplicationEvent;//定义一个事件类来表示删除操作
public class ProductDeletedEvent extends ApplicationEvent {private final Integer productId;public ProductDeletedEvent(Object source, Integer productId) {super(source);this.productId = productId;}public Integer getProductId() {return productId;}
}

ProductServiceImpl.java

package com.example.service.impl;import com.example.entity.Product;
import com.example.mapper.ProductElasticSearchMapper;
import com.example.mapper.ProductMapper;
import com.example.service.IProductService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;//空值检查:
//在处理高亮字段时,已经对highlightFields.get("productName")和highlightFields.get("productInfo")进行了空值检查,确保Product类的getProductName和getProductInfo方法也能处理可能的空值情况。
//
//字段名匹配:
//确保在Elasticsearch中定义的字段名(如productName和productInfo)与在Java代码中使用的字段名相匹配。
//
//性能考虑:
//如果productMapper.selectList(null)返回大量的产品数据,并且一次性将它们全部保存到Elasticsearch中,这可能会导致性能问题。考虑分批保存或使用Elasticsearch的批量API来提高性能。
//
//查询字符串分析:
//使用了queryStringQuery,这可能会对输入的productName进行分词查询。如果希望精确匹配整个字段值,而不是基于分词,可能需要使用termQuery或matchPhraseQuery。但是,由于处理的是全文搜索场景,queryStringQuery通常是合适的。//安全性:
//如果productName或productInfo参数来自不受信任的源(如用户输入),请确保对它们进行适当的验证和清理,以防止SQL注入或Elasticsearch注入攻击。不过,由于是在应用层进行Elasticsearch查询,而不是直接拼接查询字符串,因此SQL注入的风险较低。但仍然需要注意Elasticsearch注入的风险。//返回类型:
//返回了一个包含分页信息和搜索结果的Map。确保前端或调用此服务的客户端知道如何解析这个Map。考虑定义一个DTO(数据传输对象)来封装返回的数据,以提供更明确的契约。/*** <p>*  服务实现类* </p>** @author dd* @since 2024-05-07*/
@Service
public class ProductServiceImpl  implements IProductService {@Autowiredprivate ProductMapper productMapper;@Autowiredprivate ProductElasticSearchMapper productElasticSearchMapper;@Autowiredprivate ElasticsearchRestTemplate restTemplate;@Autowiredprivate ApplicationEventPublisher applicationEventPublisher;// 把mysql中的数据查询出来,保存商品数据到es中//当前代码逻辑中的saveProductFromDBToES方法设计为一个全量同步操作,它会从MySQL数据库中查询所有产品记录,并将它们全部保存到Elasticsearch中。因此,当从数据库中删除一条记录时,该方法不会意识到有记录被删除,因为它仅仅是再次执行了全量查询和保存操作。////为了解决这个问题,可以采取以下几种策略之一:////增量同步:设计一个机制来跟踪数据库中的更改(如使用数据库的binlog日志),并仅同步自上次同步以来发生的更改。这通常比较复杂,但可以实现实时或近实时的数据同步。////定期全量同步:可以定期(如每小时、每天)运行saveProductFromDBToES方法来进行全量同步。这种方法比较简单,但可能会导致数据在一定时间窗口内不同步。////删除操作同步:在应用程序中添加逻辑,以便在数据库记录被删除时,也在Elasticsearch中删除相应的文档。这通常需要在数据库删除操作的地方添加额外的代码或使用触发器。////使用监听器或事件驱动:如果使用的是支持事件驱动或变更数据捕获(CDC)的数据库或框架,可以配置监听器来捕获数据库更改事件,并据此更新Elasticsearch中的数据。@Overridepublic boolean saveProductFromDBToES() {//1. select  product  from mysqlList<Product> productList =    productMapper.selectList(null);//2.  save to esIterable<Product> products = productElasticSearchMapper.saveAll(productList);return true;}@Overridepublic String deleteProduct(Integer productId) {// 这里有一个方法来删除数据库中的记录int rows = productMapper.deleteById(productId);if(rows>0){// 发布删除事件applicationEventPublisher.publishEvent(new ProductDeletedEvent(this, productId));return "删除成功";}return "删除失败";}//创建一个事件监听器来监听ProductDeletedEvent并执行删除Elasticsearch中的记录的操作//ElasticsearchSyncListener类是一个Spring组件,它使用@EventListener注解来标记handleProductDeletedEvent方法作为事件监听器。当ProductDeletedEvent事件被发布时,这个方法将被调用,并执行删除Elasticsearch中相应记录的操作。////请注意,需要确保ApplicationEventPublisher和ProductElasticSearchMapper都被正确地注入到相应的类中。此外,可能还需要配置Spring的事件支持,但通常情况下,在Spring Boot应用程序中,事件支持是默认启用的。////最后,当调用ProductService的deleteProduct方法时,它将删除数据库中的记录并发布一个ProductDeletedEvent事件。这个事件将被ElasticsearchSyncListener监听并处理,从而删除Elasticsearch中的相应记录。// 实现接口方法,基于Elasticsearch的全文搜索,包括分词和高亮功能@Overridepublic Map<String,Object> getByNameAndInfo(String productName, String productInfo, Integer pageNum) {//设置分页信息,每页显示3条记录,pageNum-1是因为页码通常从1开始,而数组索引从0开始PageRequest page = PageRequest.of(pageNum - 1, 3);//创建一个布尔查询构建器,用于组合多个查询条件BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();//如果productName不为空,则创建一个基于productName的查询,并将其添加到布尔查询中if(productName !=null){QueryBuilder queryBuilder = QueryBuilders.queryStringQuery(productName);boolQueryBuilder.must(queryBuilder);}else{//如果productName为空且productInfo不为空,则创建一个基于productInfo的匹配查询,并将其添加到布尔查询中if(productInfo !=null)boolQueryBuilder.must(new MatchQueryBuilder("productInfo",productInfo));}//根据商品价格降序排序SortBuilder sortBuilder = SortBuilders.fieldSort("productPrice").order(SortOrder.DESC);//FieldSortBuilder priceSort = SortBuilders.fieldSort("productPrice"); // 按产品价格排序(需要指定升序或降序)//构建高亮查询,设置高亮字段和高亮标签NativeSearchQueryBuilder builder=new NativeSearchQueryBuilder();NativeSearchQuery query=builder.withQuery(boolQueryBuilder).withPageable(page).withSort(sortBuilder).withHighlightFields(new HighlightBuilder.Field("productInfo"),new HighlightBuilder.Field("productName")).withHighlightBuilder(new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>")).build();// 执行查询,获取搜索结果SearchHits<Product> search = restTemplate.search(query, Product.class);List<Product> productList= new ArrayList<>();//遍历搜索结果,处理高亮信息,并将处理后的产品添加到列表中for(SearchHit<Product> searchHit:search){//获取高亮字段信息Map<String ,List<String>> highlightFields = searchHit.getHighlightFields();//将高亮的内容填充到content中//处理产品名称和产品信息的高亮信息,并将其设置回产品对象中String highLightProName = highlightFields.get("productName") ==null ?searchHit.getContent().getProductName() :highlightFields.get("productName").get(0);String highLightProInfo = highlightFields.get("productInfo") ==null ?searchHit.getContent().getProductInfo() :highlightFields.get("productInfo").get(0);searchHit.getContent().setProductName(highLightProName );searchHit.getContent().setProductInfo(highLightProInfo);//将处理后的产品添加到列表中productList.add(searchHit.getContent());}//创建SearchPage对象,用于获取分页信息(假设SearchHitSupport是有效的)SearchPage<Product> searchPage= SearchHitSupport.searchPageFor(search,query.getPageable());//总记录数long totalElements=searchPage.getTotalElements();//总页数int totalPages=searchPage.getTotalPages();//当前页数int currentPageForDisplay=searchPage.getPageable().getPageNumber() + 1;// 通常前端期望页码从1开始System.out.println(currentPageForDisplay);//创建一个Map对象,用于返回查询结果和分页信息Map<String,Object> map=new HashMap<>();map.put("totalElements",totalElements);  // 总记录数map.put("totalPages",totalPages);  //总页数map.put("currentPage",currentPageForDisplay);  // 当前页码map.put("productList",productList);  // 商品数据信息//返回查询结果和分页信息的Map对象return map;}}

SyncProductService.java


package com.example.service.impl;import com.example.service.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;@Service
public class SyncProductService {@Autowiredprivate IProductService productService;@Scheduled(fixedRate = 2000) // 单位是毫秒public void syncProductsFromDBToES() {productService.saveProductFromDBToES();}
}

IProductService.java

package com.example.service;import com.example.entity.Product;
import com.baomidou.mybatisplus.extension.service.IService;import java.util.Map;/*** <p>*  服务类* </p>** @author dd* @since 2024-05-07*/
public interface IProductService  {public boolean saveProductFromDBToES();public String deleteProduct(Integer productId);// 搜索引擎中的关键字// 返回满足条件的商品的数据+分页信息public Map<String,Object> getByNameAndInfo(String productName, String productInfo, Integer pageNum);}

ElasticSearchSpringDemoApplication.java

package com.example;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@MapperScan("com.example.mapper")
@EnableScheduling
public class ElasticSearchSpringDemoApplication {public static void main(String[] args) {SpringApplication.run(ElasticSearchSpringDemoApplication.class, args);}}

ServletInitializer.java

package com.example;import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;public class ServletInitializer extends SpringBootServletInitializer {@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(ElasticSearchSpringDemoApplication.class);}}

product.sql


/*Navicat Premium Data TransferSource Server         : rootWindowsSource Server Type    : MySQLSource Server Version : 80036Source Host           : localhost:3306Source Schema         : cloud_product_dbTarget Server Type    : MySQLTarget Server Version : 80036File Encoding         : 65001Date: 07/05/2024 18:49:44
*/SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for product
-- ----------------------------
DROP TABLE IF EXISTS `product`;
CREATE TABLE `product`  (`product_id` int(0) NOT NULL AUTO_INCREMENT,`product_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`product_price` decimal(10, 2) NULL DEFAULT NULL,`product_img` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,`product_count` int(0) NULL DEFAULT NULL,`create_time` datetime(0) NULL DEFAULT NULL,`update_time` datetime(0) NULL DEFAULT NULL,`product_info` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,PRIMARY KEY (`product_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of product
-- ----------------------------SET FOREIGN_KEY_CHECKS = 1;

同步


增量同步:设计一个机制来跟踪数据库中的更改(如使用数据库的binlog日志),并仅同步自上次同步以来发生的更改。这通常比较复杂,但可以实现实时或近实时的数据同步。定期全量同步:可以定期(如每小时、每天)运行saveProductFromDBToES方法来进行全量同步。这种方法比较简单,但可能会导致数据在一定时间窗口内不同步。删除操作同步:在应用程序中添加逻辑,以便在数据库记录被删除时,也在Elasticsearch中删除相应的文档。这通常需要在数据库删除操作的地方添加额外的代码或使用触发器。使用监听器或事件驱动:如果使用的是支持事件驱动或变更数据捕获(CDC)的数据库或框架,可以配置监听器来捕获数据库更改事件,并据此更新Elasticsearch中的数据。

ProductMapper.xml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.ProductMapper"></mapper>

application.yaml


# ???
server:servlet:context-path: /es_demospring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/cloud_product_db?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456elasticsearch:uris: localhost:9200connection-timeout: 5ssocket-timeout: 30s

pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>elasticSearchSpringDemo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><name>elasticSearchSpringDemo</name><description>elasticSearchSpringDemo</description><properties><java.version>1.8</java.version></properties><dependencies><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.2</version></dependency><!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-generate --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>8.11.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

http://www.ppmy.cn/ops/36860.html

相关文章

Windows系统和unbtun系统连接usb 3.0海康可见MVS和红外艾睿相机

一.海康可见USB3.0工业面阵相机 海康usb相机需要去海康官网上下载对应系统的MVS客户端及SDK开发包 海康机器人-机器视觉-下载中心 选择Windows系统和unbtun&#xff08;我是linux aarch64,所以选择了对应压缩包解压&#xff09; Windows系统 1.双击安装包进入安装界面&…

Laravel Sail

先创建一个laravel应用&#xff0c;就先用他取的默认名字 example.com ./vendor/bin/sail up -d [] Running 6/6 ✔ Container example-app-mailpit-1 Running …

【二叉树算法题记录】110. 平衡二叉树

题目描述 给定一个二叉树&#xff0c;判断它是否是平衡二叉树。 什么是平衡二叉树&#xff1f;一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。 题目分析 其实平衡二叉树的定义就给出了递归的思路&#xff1a;每个节点的左右两个子树的高度差的绝对值不超过1。…

今日头条,抖音,西瓜视频你不知道的秘密?

西瓜视频和抖音这两款产品是一家&#xff0c;都是由今日头条孵化。 抖音是由今日头条孵化的一款音乐创意短视频社交软件&#xff0c;该软件于2016年9月20日上线&#xff0c;是一个面向全年龄的音乐短视频社区平台。用户可以通过这款软件选择歌曲&#xff0c;拍摄音乐短视频&am…

什么是虚拟货币?

随着科技的进步&#xff0c;虚拟货币逐渐进入公众视野&#xff0c;其影响深远且复杂。本文将从专业角度分析虚拟货币的发展现状、未来趋势&#xff0c;以及面临的挑战&#xff0c;并尝试提出一些思考。 一、虚拟货币的定义与现状 虚拟货币是一种基于区块链技术的数字资产&…

《Effective Java》如果说我需要一本Java编程的书,那就是它了

《Effective Java》 编写出更优雅的Java代码作者简介斩获Jolt图书大奖本文福利 编写出更优雅的Java代码 《Effective Java》是Java编程领域的一本经典之作&#xff0c;由Joshua Bloch撰写&#xff0c;旨在帮助Java程序员提高编码技巧&#xff0c;写出更加健壮、高效和易于维护的…

刷题《面试经典150题》(第九天)

加油&#xff01; 学习目标&#xff1a;学习内容&#xff1a;学习时间&#xff1a;知识点学习内容&#xff1a;跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09;H 指数 - 力扣&#xff08;LeetCode&#xff09;盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09;矩阵置…

毕业就业信息|基于Springboot+vue的毕业就业信息管理系统的设计与实现(源码+数据库+文档)

毕业就业信息管理系统 目录 基于Springboot&#xff0b;vue的毕业就业信息管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1学生信息管理 2 公司信息管理 3公告类型管理 4公告信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设…