当前位置: 首页 > news >正文

豆瓣电影后端设计

sql脚本

-- douban.tags_encode definitionCREATE TABLE `tags_encode` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',`tag` varchar(100) NOT NULL COMMENT 'tag中文名',`tag_encode` varchar(100) NOT NULL COMMENT 'tag转encode',`type` varchar(100) NOT NULL DEFAULT 'movie' COMMENT '类型:movie、tv',PRIMARY KEY (`id`),UNIQUE KEY `tags_encode_un` (`tag`,`type`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='电影中文标签与encode后关系';-- douban.movie definitionCREATE TABLE `movie` (`id` bigint NOT NULL COMMENT '主键id,同步过来',`episodes_info` varchar(100) DEFAULT NULL COMMENT 'episodes_info',`rate` varchar(10) DEFAULT NULL COMMENT '评分',`cover_x` int DEFAULT NULL COMMENT '横坐标',`title` varchar(50) NOT NULL COMMENT '电影标题',`url` varchar(100) NOT NULL COMMENT 'url地址',`playable` tinyint(1) NOT NULL COMMENT '是否可播放',`cover` varchar(100) NOT NULL COMMENT '图片地址',`cover_y` varchar(100) DEFAULT NULL COMMENT '纵坐标',`is_new` tinyint(1) NOT NULL COMMENT '是否为新上瘾',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='电影主表';INSERT INTO douban.tags_encode (tag,tag_encode,`type`) VALUES('热门','%E7%83%AD%E9%97%A8','movie'),('最新','%E6%9C%80%E6%96%B0','movie'),('豆瓣高分','%E8%B1%86%E7%93%A3%E9%AB%98%E5%88%86','movie'),('冷门佳片','%E5%86%B7%E9%97%A8%E4%BD%B3%E7%89%87','movie'),('华语','%E5%8D%8E%E8%AF%AD','movie'),('欧美','%E6%AC%A7%E7%BE%8E','movie'),('韩国','%E9%9F%A9%E5%9B%BD','movie'),('日本','%E6%97%A5%E6%9C%AC','movie'),('热门','%E7%83%AD%E9%97%A8','tv'),('国产剧','%E5%9B%BD%E4%BA%A7%E5%89%A7','tv');
INSERT INTO douban.tags_encode (tag,tag_encode,`type`) VALUES('综艺','%E7%BB%BC%E8%89%BA','tv'),('美剧','%E7%BE%8E%E5%89%A7','tv'),('日剧','%E6%97%A5%E5%89%A7','tv'),('韩剧','%E9%9F%A9%E5%89%A7','tv'),('日本动画','%E6%97%A5%E6%9C%AC%E5%8A%A8%E7%94%BB','tv'),('纪录片','%E7%BA%AA%E5%BD%95%E7%89%87','tv');

获取所有电影标签:

https://movie.douban.com/j/search_tags?type=movie&source=index

获取所有tv标签:

https://movie.douban.com/j/search_tags?type=tv&source=index

获取所有热门标签电影:

 https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=500&page_start=0

--------------------------------------------------------------------------------------------------------

current->config->DoubanDbConfig

package com.pj.current.config;import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;/*** 从数据源配置* 若需要配置更多数据源 , 直接在yml中添加数据源配置再增加相应的新的数据源配置类即可*/
@Configuration
@MapperScan(basePackages  = DoubanDbConfig.PACKAGE , sqlSessionFactoryRef = "doubanClusterSqlSessionFactory")
public class DoubanDbConfig {private Logger logger = LoggerFactory.getLogger(DoubanDbConfig.class);// 精确到 cluster 目录,以便跟其他数据源隔离static final String PACKAGE = "com.pj.project.douban";private static final String MAPPER_LOCATION = "classpath*:mapper/douban/*.xml";private static final String DOMAIN_PACKAGE = "com.pj.project.douban";@Value("${spring.datasource.url5}")private String dbUrl;@Value("${spring.datasource.username2}")private String username;@Value("${spring.datasource.password2}")private String password;@Value("${spring.datasource.driverClassName}")private String driverClassName;@Bean(name="doubanClusterDataSource")   //声明其为Bean实例public DataSource clusterDataSource() {DruidDataSource datasource = new DruidDataSource();datasource.setUrl(this.dbUrl);datasource.setUsername(username);datasource.setPassword(password);datasource.setDriverClassName(driverClassName);return datasource;}@Bean(name = "doubanClusterTransactionManager")public DataSourceTransactionManager clusterTransactionManager() {return new DataSourceTransactionManager(clusterDataSource());}@Bean(name = "doubanClusterSqlSessionFactory")public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("doubanClusterDataSource") DataSource culsterDataSource)throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(culsterDataSource);sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(DoubanDbConfig.MAPPER_LOCATION));sessionFactory.setTypeAliasesPackage(DOMAIN_PACKAGE);//mybatis 数据库字段与实体类属性驼峰映射配置sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);return sessionFactory.getObject();}
}

MovieMapper

package com.pj.project.douban.movie;import java.util.List;import com.pj.models.so.SoMap;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;/*** Mapper: movie -- 电影主表* @author lizhihao */@Mapper
@Repository
public interface MovieMapper {/*** 增  * @param m 实体对象 * @return 受影响行数 */int add(Movie m);/*** 删  * @param id 要删除的数据id  * @return 受影响行数 */int delete(Long id);	 /** * 改  * @param m 实体对象 * @return 受影响行数 */int update(Movie m);/** * 查 - 根据id  * @param id 要查询的数据id * @return 实体对象 */Movie getById(Long id);	 /*** 查集合 - 根据条件(参数为空时代表忽略指定条件)* @param so 参数集合 * @return 数据列表 */List<Movie> getList(SoMap so);void batchInsertMovieAll(List<Movie> list);void deleteAll();
}

DoubanMovieService

package com.pj.project.douban.movie;import cn.hutool.core.net.URLEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class DoubanMovieService {private static final String BASE_URL = "https://movie.douban.com/j/";private static final String TAG_URL = "search_tags?type={type}&source={source}";private static final String MOVIE_URL = "search_subjects?type={type}&tag={tag}&page_limit={page_limit}}&page_start={page_start}";@Autowiredprivate RestTemplate restTemplate;public List<String> getTags(){List<String> result = new ArrayList<>(100);Map<String, String> movieMap = new HashMap<>(10);movieMap.put("type","movie");movieMap.put("source","index");List<String> movieTags = restTemplate.getForObject(BASE_URL + TAG_URL, List.class,movieMap);Map<String, String> tvMap = new HashMap<>(10);tvMap.put("type","tv");tvMap.put("source","index");List<String> tvTags = restTemplate.getForObject(BASE_URL + TAG_URL, List.class,tvMap);result.addAll(movieTags);result.addAll(tvTags);return result;}public List<Movie> getMovies(String tag,int page_start,int page_limit){Map<String, Object> movieMap = new HashMap<>(10);movieMap.put("type","movie");URLEncoder urlEncoder = new URLEncoder();String encodeTag = urlEncoder.encode(tag, Charset.defaultCharset());movieMap.put("tag",encodeTag);movieMap.put("page_start",page_start);movieMap.put("page_limit",page_limit);return restTemplate.getForObject(BASE_URL + MOVIE_URL, List.class,movieMap);}}

Movie

package com.pj.project.douban.movie;import java.io.Serializable;import lombok.Data;
import lombok.experimental.Accessors;/*** Model: movie -- 电影主表* @author lizhihao */
@Data
@Accessors(chain = true)
public class Movie implements Serializable {// ---------- 模块常量 ----------/*** 序列化版本id */private static final long serialVersionUID = 1L;	/*** 此模块对应的表名 */public static final String TABLE_NAME = "movie";	/*** 此模块对应的权限码 */public static final String PERMISSION_CODE = "movie";	// ---------- 表中字段 ----------/*** 主键id,同步过来 */public Long id;	/*** episodes_info */public String episodesInfo;	/*** 评分 */public String rate;	/*** 横坐标 */public Integer coverX;	/*** 电影标题 */public String title;	/*** url地址 */public String url;	/*** 是否可播放 */public String playable;	/*** 图片地址 */public String cover;	/*** 纵坐标 */public String coverY;	/*** 是否为新上瘾 */public String isNew;	}

MovieController

package com.pj.project.douban.movie;import java.util.List;import com.pj.models.so.SoMap;
import com.pj.project.douban.Douban_SP;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.pj.utils.sg.*;
import com.pj.current.satoken.StpUserUtil;
import cn.dev33.satoken.annotation.SaCheckPermission;/*** Controller: movie -- 电影主表* @author lizhihao */
@RestController
@RequestMapping("/v2/movie/")
public class MovieController {/** 底层 Service 对象 */@AutowiredMovieService movieService;/** 增 */  @RequestMapping("add")@SaCheckPermission(Movie.PERMISSION_CODE)@Transactional(rollbackFor = Exception.class)public AjaxJson add(Movie m){movieService.add(m);m = movieService.getById(Douban_SP.publicMapper.getPrimarykey());return AjaxJson.getSuccessData(m);}/** 删 */  @RequestMapping("delete")@SaCheckPermission(Movie.PERMISSION_CODE)public AjaxJson delete(Long id){int line = movieService.delete(id);return AjaxJson.getByLine(line);}/** 删 - 根据id列表 */  @RequestMapping("deleteByIds")@SaCheckPermission(Movie.PERMISSION_CODE)public AjaxJson deleteByIds(){List<Long> ids = SoMap.getRequestSoMap().getListByComma("ids", long.class);int line = Douban_SP.publicMapper.deleteByIds(Movie.TABLE_NAME, ids);return AjaxJson.getByLine(line);}/** 改 */  @RequestMapping("update")@SaCheckPermission(Movie.PERMISSION_CODE)public AjaxJson update(Movie m){int line = movieService.update(m);return AjaxJson.getByLine(line);}/** 查 - 根据id */  @RequestMapping("getById")public AjaxJson getById(Long id){Movie m = movieService.getById(id);return AjaxJson.getSuccessData(m);}/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  @RequestMapping("getList")public AjaxJson getList() { SoMap so = SoMap.getRequestSoMap();List<Movie> list = movieService.getList(so.startPage());return AjaxJson.getPageData(so.getDataCount(), list);}@GetMapping("in_theaters")public AjaxJson in_theaters(@RequestParam("start") int start,@RequestParam("count") int count){SoMap so = SoMap.getRequestSoMap();so.set("pageNo",start);so.set("pageSize",count);List<Movie> list = movieService.getList(so.startPage());return AjaxJson.getSuccessData(list);}@GetMapping("coming_soon")public AjaxJson coming_soon(@RequestParam("start") int start,@RequestParam("count") int count){SoMap so = SoMap.getRequestSoMap();so.set("pageNo",start);so.set("pageSize",count);List<Movie> list = movieService.getList(so.startPage());return AjaxJson.getSuccessData(list);}@GetMapping("top250")public AjaxJson top250(@RequestParam("start") int start,@RequestParam("count") int count){SoMap so = SoMap.getRequestSoMap();so.set("pageNo",start);so.set("pageSize",count);List<Movie> list = movieService.getList(so.startPage());return AjaxJson.getSuccessData(list);}// ------------------------- 前端接口 -------------------------/** 改 - 不传不改 [G] */@RequestMapping("updateByNotNull")public AjaxJson updateByNotNull(Long id){AjaxError.throwBy(true, "如需正常调用此接口,请删除此行代码");// 鉴别身份,是否为数据创建者 long userId = Douban_SP.publicMapper.getColumnByIdToLong(Movie.TABLE_NAME, "user_id", id);AjaxError.throwBy(userId != StpUserUtil.getLoginIdAsLong(), "此数据您无权限修改");// 开始修改 (请只保留需要修改的字段)SoMap so = SoMap.getRequestSoMap();so.clearNotIn("id", "episodesInfo", "rate", "coverX", "title", "url", "playable", "cover", "coverY", "isNew").clearNull().humpToLineCase();	int line = Douban_SP.publicMapper.updateBySoMapById(Movie.TABLE_NAME, so, id);return AjaxJson.getByLine(line);}}

MovieService

package com.pj.project.douban.movie;import java.util.List;
import com.pj.models.so.SoMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;/*** Service: movie -- 电影主表* @author lizhihao */
@Service
public class MovieService {/** 底层 Mapper 对象 */@AutowiredMovieMapper movieMapper;@Autowiredprivate DoubanMovieService doubanMovieService;/** 增 */int add(Movie m){return movieMapper.add(m);}/** 删 */int delete(Long id){return movieMapper.delete(id);}/** 改 */int update(Movie m){return movieMapper.update(m);}/** 查 */Movie getById(Long id){return movieMapper.getById(id);}/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  List<Movie> getList(SoMap so) {return movieMapper.getList(so);	}public void batchInsertMovieAll(){List<String> tags = doubanMovieService.getTags();if(CollectionUtils.isEmpty(tags)){return;}tags.stream().forEach(v->{// 每种类型大概 100000w 条数据int perTagMaxSize = 100000;int pageLimit = 1000;for (int i = 0; i < perTagMaxSize; i+=pageLimit) {List<Movie> movies = doubanMovieService.getMovies(v, i, i + pageLimit);movieMapper.batchInsertMovieAll(movies);}});}public void deleteAll(){movieMapper.deleteAll();}}

MovieUtil

package com.pj.project.douban.movie;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.pj.utils.sg.*;/*** 工具类:movie -- 电影主表* @author lizhihao **/
@Component
public class MovieUtil {/** 底层 Mapper 对象 */public static MovieMapper movieMapper;@Autowiredprivate void setMovieMapper(MovieMapper movieMapper) {MovieUtil.movieMapper = movieMapper;}/** * 将一个 Movie 对象进行进行数据完整性校验 (方便add/update等接口数据校验) [G] */static void check(Movie m) {AjaxError.throwByIsNull(m.id, "[主键id,同步过来] 不能为空");		// 验证: 主键id,同步过来 AjaxError.throwByIsNull(m.episodesInfo, "[episodes_info] 不能为空");		// 验证: episodes_info AjaxError.throwByIsNull(m.rate, "[评分] 不能为空");		// 验证: 评分 AjaxError.throwByIsNull(m.coverX, "[横坐标] 不能为空");		// 验证: 横坐标 AjaxError.throwByIsNull(m.title, "[电影标题] 不能为空");		// 验证: 电影标题 AjaxError.throwByIsNull(m.url, "[url地址] 不能为空");		// 验证: url地址 AjaxError.throwByIsNull(m.playable, "[是否可播放] 不能为空");		// 验证: 是否可播放 AjaxError.throwByIsNull(m.cover, "[图片地址] 不能为空");		// 验证: 图片地址 AjaxError.throwByIsNull(m.coverY, "[纵坐标] 不能为空");		// 验证: 纵坐标 AjaxError.throwByIsNull(m.isNew, "[是否为新上瘾] 不能为空");		// 验证: 是否为新上瘾 }/** * 获取一个Movie (方便复制代码用) [G] */ static Movie getMovie() {Movie m = new Movie();	// 声明对象 m.id = 0L;		// 主键id,同步过来 m.episodesInfo = "";		// episodes_info m.rate = "";		// 评分 m.coverX = 0;		// 横坐标 m.title = "";		// 电影标题 m.url = "";		// url地址 m.playable = "";		// 是否可播放 m.cover = "";		// 图片地址 m.coverY = "";		// 纵坐标 m.isNew = "";		// 是否为新上瘾 return m;}}

TagsEncodeMapper

package com.pj.project.douban.tags_encode;import java.util.List;import com.pj.models.so.SoMap;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;/*** Mapper: tags_encode -- 电影中文标签与encode后关系* @author lizhihao */@Mapper
@Repository
public interface TagsEncodeMapper {/*** 增  * @param t 实体对象 * @return 受影响行数 */int add(TagsEncode t);/*** 删  * @param id 要删除的数据id  * @return 受影响行数 */int delete(Long id);	 /** * 改  * @param t 实体对象 * @return 受影响行数 */int update(TagsEncode t);/** * 查 - 根据id  * @param id 要查询的数据id * @return 实体对象 */TagsEncode getById(Long id);	 /*** 查集合 - 根据条件(参数为空时代表忽略指定条件)* @param so 参数集合 * @return 数据列表 */List<TagsEncode> getList(SoMap so);}

TagsEncode

package com.pj.project.douban.tags_encode;import java.io.Serializable;import lombok.Data;
import lombok.experimental.Accessors;/*** Model: tags_encode -- 电影中文标签与encode后关系* @author lizhihao */
@Data
@Accessors(chain = true)
public class TagsEncode implements Serializable {// ---------- 模块常量 ----------/*** 序列化版本id */private static final long serialVersionUID = 1L;	/*** 此模块对应的表名 */public static final String TABLE_NAME = "tags_encode";	/*** 此模块对应的权限码 */public static final String PERMISSION_CODE = "tags-encode";	// ---------- 表中字段 ----------/*** 自增主键 */public Long id;	/*** tag中文名 */public String tag;	/*** tag转encode */public String tagEncode;	/*** 类型:movie、tv */public String type;	}

TagsEncodeController

package com.pj.project.douban.tags_encode;import java.util.List;import com.pj.models.so.SoMap;
import com.pj.project.douban.Douban_SP;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.pj.utils.sg.*;
import com.pj.current.satoken.StpUserUtil;
import cn.dev33.satoken.annotation.SaCheckPermission;/*** Controller: tags_encode -- 电影中文标签与encode后关系* @author lizhihao */
@RestController
@RequestMapping("/TagsEncode/")
public class TagsEncodeController {/** 底层 Service 对象 */@AutowiredTagsEncodeService tagsEncodeService;/** 增 */  @RequestMapping("add")@SaCheckPermission(TagsEncode.PERMISSION_CODE)@Transactional(rollbackFor = Exception.class)public AjaxJson add(TagsEncode t){tagsEncodeService.add(t);t = tagsEncodeService.getById(Douban_SP.publicMapper.getPrimarykey());return AjaxJson.getSuccessData(t);}/** 删 */  @RequestMapping("delete")@SaCheckPermission(TagsEncode.PERMISSION_CODE)public AjaxJson delete(Long id){int line = tagsEncodeService.delete(id);return AjaxJson.getByLine(line);}/** 删 - 根据id列表 */  @RequestMapping("deleteByIds")@SaCheckPermission(TagsEncode.PERMISSION_CODE)public AjaxJson deleteByIds(){List<Long> ids = SoMap.getRequestSoMap().getListByComma("ids", long.class);int line = Douban_SP.publicMapper.deleteByIds(TagsEncode.TABLE_NAME, ids);return AjaxJson.getByLine(line);}/** 改 */  @RequestMapping("update")@SaCheckPermission(TagsEncode.PERMISSION_CODE)public AjaxJson update(TagsEncode t){int line = tagsEncodeService.update(t);return AjaxJson.getByLine(line);}/** 查 - 根据id */  @RequestMapping("getById")public AjaxJson getById(Long id){TagsEncode t = tagsEncodeService.getById(id);return AjaxJson.getSuccessData(t);}/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  @RequestMapping("getList")public AjaxJson getList() { SoMap so = SoMap.getRequestSoMap();List<TagsEncode> list = tagsEncodeService.getList(so.startPage());return AjaxJson.getPageData(so.getDataCount(), list);}// ------------------------- 前端接口 -------------------------/** 改 - 不传不改 [G] */@RequestMapping("updateByNotNull")public AjaxJson updateByNotNull(Long id){AjaxError.throwBy(true, "如需正常调用此接口,请删除此行代码");// 鉴别身份,是否为数据创建者 long userId = Douban_SP.publicMapper.getColumnByIdToLong(TagsEncode.TABLE_NAME, "user_id", id);AjaxError.throwBy(userId != StpUserUtil.getLoginIdAsLong(), "此数据您无权限修改");// 开始修改 (请只保留需要修改的字段)SoMap so = SoMap.getRequestSoMap();so.clearNotIn("id", "tag", "tagEncode", "type").clearNull().humpToLineCase();	int line = Douban_SP.publicMapper.updateBySoMapById(TagsEncode.TABLE_NAME, so, id);return AjaxJson.getByLine(line);}}

TagsEncodeService

package com.pj.project.douban.tags_encode;import java.util.List;import com.pj.models.so.SoMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** Service: tags_encode -- 电影中文标签与encode后关系* @author lizhihao */
@Service
public class TagsEncodeService {/** 底层 Mapper 对象 */@AutowiredTagsEncodeMapper tagsEncodeMapper;/** 增 */int add(TagsEncode t){return tagsEncodeMapper.add(t);}/** 删 */int delete(Long id){return tagsEncodeMapper.delete(id);}/** 改 */int update(TagsEncode t){return tagsEncodeMapper.update(t);}/** 查 */TagsEncode getById(Long id){return tagsEncodeMapper.getById(id);}/** 查集合 - 根据条件(参数为空时代表忽略指定条件) */  List<TagsEncode> getList(SoMap so) {return tagsEncodeMapper.getList(so);	}}

TagsEncodeUtil

package com.pj.project.douban.tags_encode;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import com.pj.utils.sg.*;/*** 工具类:tags_encode -- 电影中文标签与encode后关系* @author lizhihao **/
@Component
public class TagsEncodeUtil {/** 底层 Mapper 对象 */public static TagsEncodeMapper tagsEncodeMapper;@Autowiredprivate void setTagsEncodeMapper(TagsEncodeMapper tagsEncodeMapper) {TagsEncodeUtil.tagsEncodeMapper = tagsEncodeMapper;}/** * 将一个 TagsEncode 对象进行进行数据完整性校验 (方便add/update等接口数据校验) [G] */static void check(TagsEncode t) {AjaxError.throwByIsNull(t.id, "[自增主键] 不能为空");		// 验证: 自增主键 AjaxError.throwByIsNull(t.tag, "[tag中文名] 不能为空");		// 验证: tag中文名 AjaxError.throwByIsNull(t.tagEncode, "[tag转encode] 不能为空");		// 验证: tag转encode AjaxError.throwByIsNull(t.type, "[类型:movie、tv] 不能为空");		// 验证: 类型:movie、tv }/** * 获取一个TagsEncode (方便复制代码用) [G] */ static TagsEncode getTagsEncode() {TagsEncode t = new TagsEncode();	// 声明对象 t.id = 0L;		// 自增主键 t.tag = "";		// tag中文名 t.tagEncode = "";		// tag转encode t.type = "";		// 类型:movie、tv return t;}}

Douban_SP

package com.pj.project.douban;import com.fasterxml.jackson.databind.ObjectMapper;
import com.pj.project.sp_dev.public4mapper.PublicMapper;
import com.pj.project.sp_dev.public4mapper.PublicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** 公共Mapper 与 公共Service * @author kong**/
@Component
public class Douban_SP {/*** 公共Mapper*/public static PublicMapper publicMapper;	/*** 公共Service*/public static PublicService publicService;				/*** json序列化对象 */public static ObjectMapper objectMapper;// 注入 @Autowiredpublic void setBean(PublicMapper publicMapper,PublicService publicService,ObjectMapper objectMapper) {Douban_SP.publicMapper = publicMapper;Douban_SP.publicService = publicService;Douban_SP.objectMapper = objectMapper;}}

DoubanFC

package com.pj.project.douban;import com.pj.project.douban.movie.MovieMapper;
import com.pj.project.douban.movie.MovieService;
import com.pj.project.sp_dev.public4mapper.PublicMapper;
import com.pj.project.sp_dev.public4mapper.PublicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class DoubanFC {// ======================================== 所有Mapper ==============================================public static MovieMapper movieMapper;		// Mapper:电影主表public static PublicMapper publicMapper;					// Mapper: 公共Mapper// ======================================== 所有Service ==============================================public static MovieService movieService;		// Service:电影主表public static PublicService publicService;						// Service:公共service// ======================================== 所有注入所有Bean ==============================================// 注入@Autowiredpublic void setBean(MovieMapper movieMapper,PublicMapper publicMapper,MovieService movieService,PublicService publicService) {DoubanFC.movieMapper = movieMapper;DoubanFC.publicMapper = publicMapper;DoubanFC.movieService = movieService;DoubanFC.publicService = publicService;}
}

DoubanMovieTask

package com.pj.task;import com.pj.project.douban.movie.MovieService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;@Slf4j
@Component
public class DoubanMovieTask {@Autowiredprivate MovieService movieService;@Scheduled(cron = "0 0 23 * * ?")@Transactional(rollbackFor = Exception.class)public void syncAllMovie() {try{//先删除所有数据movieService.deleteAll();movieService.batchInsertMovieAll();}catch (Exception e){log.error("同步失败", e);throw new RuntimeException("同步失败");}}}

MovieMapper.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.pj.project.douban.movie.MovieMapper"><!-- 增 [G] --><insert id="add">insert into movie (id, episodes_info, rate, cover_x, title, url, playable, cover, cover_y, is_new) values (#{id}, #{episodesInfo}, #{rate}, #{coverX}, #{title}, #{url}, #{playable}, #{cover}, #{coverY}, #{isNew}) </insert><insert id="batchInsertMovieAll" parameterType="java.util.List">insert intomovie (id, episodes_info, rate, cover_x, title, url, playable, cover, cover_y, is_new)VALUES<foreach collection="list" item="l" separator=",">(#{l.id}, #{l.episodesInfo}, #{l.rate}, #{l.coverX}, #{l.title}, #{l.url}, #{l.playable}, #{l.cover}, #{l.coverY}, #{l.isNew})</foreach></insert><!-- 删 --><delete id="delete">delete from movie where id = #{id}</delete><delete id="deleteAll">delete from movie</delete><!-- 改 [G] --><update id="update">update movie setid = #{id}, episodes_info = #{episodesInfo}, rate = #{rate}, cover_x = #{coverX}, title = #{title}, url = #{url}, playable = #{playable}, cover = #{cover}, cover_y = #{coverY}, is_new = #{isNew}where id = #{id}</update><!-- ================================== 查询相关 ================================== --><!-- select id, episodes_info, rate, cover_x, title, url, playable, cover, cover_y, is_new from movie  --><!-- 通用映射:手动模式 --><resultMap id="model" type="com.pj.project.douban.movie.Movie"><result property="id" column="id" /><result property="episodesInfo" column="episodes_info" /><result property="rate" column="rate" /><result property="coverX" column="cover_x" /><result property="title" column="title" /><result property="url" column="url" /><result property="playable" column="playable" /><result property="cover" column="cover" /><result property="coverY" column="cover_y" /><result property="isNew" column="is_new" /></resultMap><!-- 公共查询sql片段 --><sql id="select_sql">select * from movie </sql><!-- 查 - 根据id --><select id="getById" resultMap="model"><include refid="select_sql"></include>where id = #{id}</select><!-- 查集合 - 根据条件(参数为空时代表忽略指定条件) [G] --><select id="getList" resultMap="model"><include refid="select_sql"></include><where><if test=' this.has("id") '> and id = #{id} </if><if test=' this.has("episodesInfo") '> and episodes_info = #{episodesInfo} </if><if test=' this.has("rate") '> and rate = #{rate} </if><if test=' this.has("coverX") '> and cover_x = #{coverX} </if><if test=' this.has("title") '> and title = #{title} </if><if test=' this.has("url") '> and url = #{url} </if><if test=' this.has("playable") '> and playable = #{playable} </if><if test=' this.has("cover") '> and cover = #{cover} </if><if test=' this.has("coverY") '> and cover_y = #{coverY} </if><if test=' this.has("isNew") '> and is_new = #{isNew} </if></where>order by<choose><when test='sortType == 1'> id desc </when><when test='sortType == 2'> episodes_info desc </when><when test='sortType == 3'> rate desc </when><when test='sortType == 4'> cover_x desc </when><when test='sortType == 5'> title desc </when><when test='sortType == 6'> url desc </when><when test='sortType == 7'> playable desc </when><when test='sortType == 8'> cover desc </when><when test='sortType == 9'> cover_y desc </when><when test='sortType == 10'> is_new desc </when><otherwise> id desc </otherwise></choose></select></mapper>

TagsEncodeMapper.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.pj.project.douban.tags_encode.TagsEncodeMapper"><!-- 增 [G] --><insert id="add">insert into tags_encode (id, tag, tag_encode, type) values (#{id}, #{tag}, #{tagEncode}, #{type}) </insert><!-- 删 --><delete id="delete">delete from tags_encode where id = #{id}</delete><!-- 改 [G] --><update id="update">update tags_encode setid = #{id}, tag = #{tag}, tag_encode = #{tagEncode}, type = #{type}where id = #{id}</update><!-- ================================== 查询相关 ================================== --><!-- select id, tag, tag_encode, type from tags_encode  --><!-- 通用映射:手动模式 --><resultMap id="model" type="com.pj.project.douban.tags_encode.TagsEncode"><result property="id" column="id" /><result property="tag" column="tag" /><result property="tagEncode" column="tag_encode" /><result property="type" column="type" /></resultMap><!-- 公共查询sql片段 --><sql id="select_sql">select * from tags_encode </sql><!-- 查 - 根据id --><select id="getById" resultMap="model"><include refid="select_sql"></include>where id = #{id}</select><!-- 查集合 - 根据条件(参数为空时代表忽略指定条件) [G] --><select id="getList" resultMap="model"><include refid="select_sql"></include><where><if test=' this.has("id") '> and id = #{id} </if><if test=' this.has("tag") '> and tag = #{tag} </if><if test=' this.has("tagEncode") '> and tag_encode = #{tagEncode} </if><if test=' this.has("type") '> and type = #{type} </if></where>order by<choose><when test='sortType == 1'> id desc </when><when test='sortType == 2'> tag desc </when><when test='sortType == 3'> tag_encode desc </when><when test='sortType == 4'> type desc </when><otherwise> id desc </otherwise></choose></select></mapper>
        url5: jdbc:mysql://localhost:3306/douban?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTCusername5: rootpassword5: 123456

相关文章:

豆瓣电影后端设计

sql脚本 -- douban.tags_encode definitionCREATE TABLE tags_encode (id bigint NOT NULL AUTO_INCREMENT COMMENT 自增主键,tag varchar(100) NOT NULL COMMENT tag中文名,tag_encode varchar(100) NOT NULL COMMENT tag转encode,type varchar(100) NOT NULL DEFAULT movie …...

【深度学习】第1章

概论: 机器学习是对研究问题进行模型假设,利用计算机从训练数据中学习得到模型参数,并最终对数据进行预测和分析,其基础主要是归纳和统计。 深度学习是一种实现机器学习的技术,是机器学习重要的分支。其源于人工神经网络的研究。深度学习的模型结构是一种含多隐层的神经…...

Vue3实战笔记(37)—粒子特效登录页面

文章目录 前言一、粒子特效登录页总结 前言 上头了&#xff0c;再来一个粒子特效登录页面。 一、粒子特效登录页 登录页&#xff1a; <template><div><vue-particles id"tsparticles" particles-loaded"particlesLoaded" :options"…...

解锁无限可能:JavaScript与【机器学习】的浪漫邂逅

解锁无限可能&#xff1a;JavaScript与机器学习的浪漫邂逅 在人工智能和大数据日益盛行的今天&#xff0c;机器学习已成为我们理解、分析和处理数据的强大工具。而JavaScript&#xff0c;作为前端开发的主流语言&#xff0c;其灵活的特性和广泛的应用场景也让我们对其充满了期…...

【Linux】$()中的内容与不加$()时有什么区别

$()中的内容与不加$()有什么区别&#xff0c;例如$(/usr/local/hadoop/bin/hadoop classpath)与/usr/local/hadoop/bin/hadoop classpath两者有何区别&#xff1f;&#xff1f;&#xff1f; 关于这个问题&#xff0c;笔者建议可以参考如下文章&#xff1a; Linux—shell中$((…...

2024最新前端面试八股文【基础篇293题】

⼀、HTML、HTTP、web综合问题 1 前端需要注意哪些SEO 2 <img> 的 title 和 alt 有什么区别 3 HTTP的⼏种请求⽅法⽤途 4 从浏览器地址栏输⼊url到显示⻚⾯的步骤 5 如何进⾏⽹站性能优化 6 HTTP状态码及其含义 7 语义化的理解 8 介绍⼀下你对浏览器内核的理解 9 …...

【NumPy】关于numpy.median()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…...

起保停电路工作原理

一、电路组成 起保停电路由电源保护设备&#xff08;空气开关&#xff09;、交流接触器、启动按钮、停止按钮和用电设备组成。 起保停电路的组成部分通常可分为四个部分&#xff1a; 保护部分&#xff1a;&#xff08;空气开关&#xff09;在电流或电压超出一定范围时自动切断…...

【Vue】Vue2使用ElementUI

目录 Element UI介绍特点Vue2使用Element安装引入ElementUI组件库 使用ElementUI用户注册列表展示其他 mint-ui介绍特点安装组件引入组件Mint-ui相关组件 Element UI 介绍 官网(基于 Vue 2.x ):https://element.eleme.cn/#/zh-CN ElementUI 是一个基于 Vue.js 的桌面端组件库…...

设计模式在芯片验证中的应用——模板方法

一、模板方法 模板方法(Template Method)设计模式是一种行为设计模式&#xff0c; 它在父类中定义了一个功能的框架&#xff0c; 允许子类在不修改结构的情况下重写功能的特定步骤。也就是模板方法定义了一组有序执行的操作&#xff0c;将一些步骤的实现留给子类&#xff0c;同…...

Webpack Bundle Analyzer:深入分析与优化你的包

Webpack Bundle Analyzer是一个用于可视化的工具&#xff0c;它可以帮助你分析Webpack打包后的输出文件&#xff0c;查看哪些模块占用了最多的空间&#xff0c;从而进行优化。 2500G计算机入门到高级架构师开发资料超级大礼包免费送&#xff01; 首先&#xff0c;你需要安装W…...

Java后端开发学习历程

1、JavaWeb------------------------>19天 2、SSMSpringBoot------------->12天 3、瑞吉外卖项目------------------>15天 4、JavaSE-------------------------->25天 总耗时71天&#xff08;2024.03.11——2024.05.26两个半月&#xff09;&#xff0c;Java后端…...

CentOS 7 socat命令端口转发

场景 开发排查问题需配置远程调试,但配置调试的服务器不支持外网访问,于是就考虑到用端口转发的方式让开发进行远程调试,转发工具比如有:rinetd等等,意外看到使用socat做转发更简单方便,下面就记录一下 命令简介 socat 是一个功能强大的网络工具,可以在两个连接的数据…...

vue全局修改设置滚动条样式

vue全局修改设置滚动条样式 具体代码&#xff1a; ::-webkit-scrollbar{ /*滚动条整体样式*/width: 6px; /*高宽分别对应横竖滚动条的尺寸*/height: 1px; } ::-webkit-scrollbar-thumb{ /*滚动条里面小方块*/border-radius: 5px;background: #cfcbcb; } ::-webkit-scrollbar-…...

​✨聚梦AI绘图插件-for photoshop(基于ComfyUI) 内测版V0.1发布

&#x1f388;背景 photoshop本身是有AI生成能力的&#xff0c;不过限于种种原因&#xff0c;国内使用很不方便。 photoshop也是有AI插件的&#xff0c;不过大多安装起来比较复杂&#xff0c;或者&#xff0c;干脆就会收费。 所以我们做了一个免费的AI插件&#xff0c;期望能…...

java “错误:编码GBK 的不可映射字符”

环境&#xff1a;JDK-17 本机编码&#xff1a;utf-8 代码编码&#xff1a;GBK 错误&#xff1a;java “错误&#xff1a;编码GBK 的不可映射字符” 解决1&#xff1a;记事本打开java源文件&#xff0c;另存为选择ANSI编码 解决2&#xff1a;复制代码再将编码格式改为utf-8,…...

前端 JS 经典:Web 性能指标

什么是性能指标&#xff1a;Web Performance Metrics 翻译成 Web 性能指标&#xff0c;一般和时间有关系&#xff0c;在短时间内做更多有意义的事情。 一个站点表现得好与不好&#xff0c;标准在于用户体验&#xff0c;而用户体验好不好&#xff0c;有一套 RAIL 模型来衡量。这…...

SVN创建分支,分支合并,切换分支。通俗易懂

1、首先在svnbucket.com远程仓库上创建项目&#xff0c;这里我创建了个测试demo&#xff1a; 2、先把svn仓库的项目检出到自己的文件夹&#xff0c;我这里是demo001文件夹&#xff0c;此时并没有创建truck, branches, tags这三个目录&#xff1a; 3、 在demo001文件夹里新建tru…...

【编译原理复习笔记】中间语言

中间语言 中间语言的特点和作用 &#xff08;1&#xff09;独立于机器 &#xff08;2&#xff09;复杂性介于源语言和目标语言之间 中间语言可以使编译程序的结构在逻辑上更为简单明确 常用的中间语言 后缀式 图表示&#xff1a;抽象语法树&#xff0c;有向无环图 三地址代…...

linux笔记6--shell相关

文章目录 1. 查看当前的shell类型2. ps -f命令3. 父子shell4. 分号在命令里的作用问题&#xff1a;环境变量echo&#xff1a; 5. sleep和jobssleep:jobs:例子&#xff1a;&: 6. 外部命令和内建命令图解外部命令type命令 7. history命令8. alias命令9. 推荐 1. 查看当前的sh…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

go 里面的指针

指针 在 Go 中&#xff0c;指针&#xff08;pointer&#xff09;是一个变量的内存地址&#xff0c;就像 C 语言那样&#xff1a; a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10&#xff0c;通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

大数据驱动企业决策智能化的路径与实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;数据驱动的企业竞争力重构 在这个瞬息万变的商业时代&#xff0c;“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...