豆瓣电影后端设计

sql脚本

sql 复制代码
-- douban.tags_encode definition

CREATE 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 definition

CREATE 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=热门\&page_limit=500\&page_start=0


current->config->DoubanDbConfig

java 复制代码
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

java 复制代码
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

java 复制代码
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}";

    @Autowired
    private 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

java 复制代码
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

java 复制代码
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 对象 */
	@Autowired
	MovieService 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

java 复制代码
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 对象 */
	@Autowired
	MovieMapper movieMapper;
	@Autowired
	private 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

java 复制代码
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;
	@Autowired
	private 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

java 复制代码
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

java 复制代码
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

java 复制代码
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 对象 */
	@Autowired
	TagsEncodeService 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

java 复制代码
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 对象 */
	@Autowired
	TagsEncodeMapper 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

java 复制代码
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;
	@Autowired
	private 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

java 复制代码
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;
	
	// 注入 
	@Autowired
	public void setBean(
			PublicMapper publicMapper,
			PublicService publicService,
			ObjectMapper objectMapper
			) {
		Douban_SP.publicMapper = publicMapper;
		Douban_SP.publicService = publicService;
		Douban_SP.objectMapper = objectMapper;
	}
	
	
	
	
}

DoubanFC

java 复制代码
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 ==============================================

    // 注入
    @Autowired
    public void setBean(
            MovieMapper movieMapper,
            PublicMapper publicMapper,

            MovieService movieService,
            PublicService publicService
    ) {
        DoubanFC.movieMapper = movieMapper;
        DoubanFC.publicMapper = publicMapper;

        DoubanFC.movieService = movieService;
        DoubanFC.publicService = publicService;
    }
}

DoubanMovieTask

java 复制代码
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 {
    @Autowired
    private 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 复制代码
<?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 into
		movie (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 set
		id = #{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 复制代码
<?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 set
		id = #{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>
java 复制代码
        url5: jdbc:mysql://localhost:3306/douban?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
        username5: root
        password5: 123456
相关推荐
y先森17 分钟前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy17 分钟前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu108301891120 分钟前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
弗拉唐1 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi771 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
BestandW1shEs1 小时前
谈谈Mysql的常见基础问题
数据库·mysql
重生之Java开发工程师1 小时前
MySQL中的CAST类型转换函数
数据库·sql·mysql
教练、我想打篮球1 小时前
66 mysql 的 表自增长锁
数据库·mysql