豆瓣电影后端设计

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
相关推荐
Java编程乐园2 分钟前
Java中以某字符串开头且忽略大小写字母如何实现【正则表达式(Regex)】
java·正则表达式
阿七想学习3 分钟前
数据结构《排序》
java·数据结构·学习·算法·排序算法
Domain-zhuo3 分钟前
如何提高webpack的构建速度?
前端·webpack·前端框架·node.js·ecmascript
xlsw_8 分钟前
java全栈day21--Web后端实战之利用Mybaits查询数据
java·开发语言
还是大剑师兰特18 分钟前
面试题:ES6模块与CommonJS模块有什么异同?
前端·es6·大剑师
什么想法都无23 分钟前
stream
java·java stream
m0_7482336423 分钟前
WebService简介
java
love静思冥想24 分钟前
Stream `Collectors.toList()` 和 `Stream.toList()` 的区别(Java)
java·stream
weisian15126 分钟前
Redis篇--常见问题篇6--缓存一致性1(Mysql和Redis缓存一致,更新数据库删除缓存策略)
数据库·redis·缓存
胡西风_foxww34 分钟前
【ES6复习笔记】数值扩展(16)
前端·笔记·es6·扩展·数值