由于多说关闭,多说源码不开放,Java模仿多说评论系统实现(二)

soゝso 2017-05-02 22:26:11 3267

先什么都不多说,先看看效果,高仿多说评论已经上线,估计还是有瑕疵,不断完善中。评论链接===> :http://www.sojson.com/other/duoshuo.html

昨天说到了  多说  ,然后简单分析了一个评论基本需求,基本的字段等等。

今天建表,初步把数据拉出来,当然功能不是很完善(后面会逐步把该有功能补上),目前实现了评论,回复评论,以及把原有的数据读取过来。下面看看简单效果图和功能。先看看数据结构,我用咱们网站的工具:http://www.sojson.com/simple_json.html  分析了下数据。


一、模拟多说评论表结构创建

主要三张表:

so_message:为评论表,所有评论都在这里,有自关联属性,为id和parent_id

so_message_like:为评论点赞(顶)表,一个authorId + 一个messageId为唯一性,也就是一条数据一个用户只能点赞一次。

so_message_author:为评论用户表,一个用户可以评论多个评论,和评论的关系是多对一的关系。

二、数据从多说同步(从多说导出的数据太烂)

多说有数据导出功能,但是导出后,我发现数据不全,而且阅读性差,加上我之前的评论不是太多,而且都是以链接为单位,所以我更偏向单个导出。

/**
 * 从多说同步数据
 * @param pkey	业务数据Key,其实就是URL
 * @return
 */
@RequestMapping(value="synchMessage",method=RequestMethod.GET)
@ResponseBody
public Map<String,Object> synchMessage(String pkey){
	
	Map<String, Object> resultMap = new LinkedHashMap<String, Object>();
	String urlKey = StringUtils.strToUrlcode(pkey);
	
	//这是一个临时表,记录这条数据是否已经同步过了
	Temp temp = tempService.selectTempByPkey(pkey);
	if(null != temp ){
		resultMap.put("status", 1);
		resultMap.put("message", "不用再加载。");
		return resultMap;
	}
	//这个就是一个普通的HTTP请求的封装
	String result = new GetJSON("http://iqingxin.duoshuo.com/api/threads/listPosts.json?thread_key=" +urlKey +"&limit=1000")
						.executeMethod(String.class);
	//转换为JSON对象
	JsonObject json = new Gson().fromJson(result, JsonObject.class);
	int total = 0;
	if(json.has("cursor")){
		JsonObject cursor = json.getAsJsonObject("cursor");
		if(null!= cursor && cursor.get("total").getAsInt() == 0 ){
			total =  cursor.get("total").getAsInt();
			//添加标记为已经获取了记录。
			tempService.insertTemp(new Temp(pkey, 0));
			resultMap.put("status", 8);
			resultMap.put("message", "已经完成。");
			return resultMap;
		}
	}
	
	//获取这一个层级即可,不需要再深的层级
	
	JsonObject parentPosts = json.getAsJsonObject("parentPosts");
	
	//json中数据条数
	int size = parentPosts.entrySet().size();
	
	//循环获取数据
	Set<Entry<String,JsonElement>> keys = parentPosts.entrySet();
	for (Entry<String,JsonElement> entry : keys) {
		JsonObject jsonObj = entry.getValue().getAsJsonObject();
		
		if(null == jsonObj.get("message") || jsonObj.get("message").isJsonNull()){
			continue;
		}
		//获取message
		String m = jsonObj.get("message").getAsString();
		if("谢谢您的反馈,已经修改!".equals(m.trim())){
			System.out.println(1);
		}
		//因为可能要执行多次,多说有BUG,有的时候不能获取所有数据
		Long id = messageService.selectByMessageAndKey(new SOMessage().setPkey(pkey).setMessage(m));
		if(null != id){
			continue;
		}
		SOMessageAuthor messageAuthor = new SOMessageAuthor(jsonObj);
		//用户信息
		String nickname = messageAuthor.getNickname();
		Long authorId = messageAuthorService.selectByNickname(nickname);
		if(null == authorId){
			messageAuthorService.insertSelective(messageAuthor);
			authorId = messageAuthor.getId();
		}
		SOMessage message = new SOMessage(jsonObj,1/*1级*/,""/*父ID串*/,new Long(0)/*父ID*/,authorId);
		message.setPkey(pkey);
		messageService.insertSelective(message);
		//获取子类。
		JsonArray childeren = jsonObj.getAsJsonArray("children");
		//存储子类数据,递归存储
		exe(childeren, message, pkey, 2);
		
		
		
		
		//添加标记为已经获取了记录。
		if(size == total){
			tempService.insertTemp(new Temp(pkey, size));
			resultMap.put("status", 8);
			resultMap.put("message", "已经完成。");
		}
	}
	
	return resultMap;

}
/**
 * 递归调用方法
 * @param childeren	子类集合
 * @param message	当前message对象
 * @param key		评论数据key 
 * @param level		评论级别
 */
private void exe(JsonArray childeren,SOMessage message ,String key,Integer level){
	if(null != childeren && childeren.isJsonArray() && childeren.size()>0 )
	A:for (JsonElement jsonElement : childeren) {
		JsonObject json = jsonElement.getAsJsonObject();
		//如果没有数据,迭代下一条
		if(null == json.get("message") || json.get("message").isJsonNull()){
			continue A;
		}
		//获取message
		String m = json.get("message").getAsString();
		
		//因为可能要执行多次,多说有BUG,有的时候不能获取所有数据
		Long id = messageService.selectByMessageAndKey(new SOMessage().setPkey(key).setMessage(m));
		if(null != id){
			continue;
		}
		Long pid = message.getParentId();
		String pids = null;
		//如果是一级,父ID为0
		if(Constant.ZERO.equals(pid)){
			pids = "," +message.getId()+"," ;
		}else{
			pids = message.getPids()  +message.getId()+",";
		}
		
		//初始化对象
		SOMessageAuthor messageAuthor = new SOMessageAuthor(json);
		//用户信息
		String nickname = messageAuthor.getNickname();
		Long authorId = messageAuthorService.selectByNickname(nickname);
		if(null == authorId){
			messageAuthorService.insertSelective(messageAuthor);
			authorId = messageAuthor.getId();
		}
		SOMessage message2 = new SOMessage(json,level,pids,message.getId()/*父ID*/,authorId);
		message2 .setPkey(key);
		//插入数据
		messageService.insertSelective(message2);
		
		
		//获取子类。
		JsonArray cs = json.getAsJsonArray("children");
		if(null != cs && cs.isJsonArray() && cs.size()>0 ){
			//递归调用
			exe(cs, message2, key, level+1);
		}
		
	}
}

三、评论实体(Entity)代码

so_message 的实体对象,包含一些业务数据转换,getter/setter 方法我就不贴出来。

/**
 * 
 * 开发公司:SOJSON在线工具 <p>
 * 版权所有:© www.sojson.com<p>
 * 博客地址:http://www.sojson.com/blog/  <p>
 * <p>
 * 
 * 模拟多说评论实体
 * 
 * <p>
 * 
 * 区分 责任人 日期    说明<br/>
 * 创建 周柏成 2017年5月2日 19:48  <br/>
 *
 * @author zhou-baicheng
 * @email  so@sojson.com
 * @version 1.0,2017年5月2日 19:48 <br/>
 * 
 */
public class SOMessage implements Serializable{
	private static final long serialVersionUID = 1434473283877857750L;
	/**评论id**/
	private Long id;
	/**创建时间**/
    private Date createdTime;
    private String createdTimeStr;
    private String createdYMDHMSStr;//年月日,时分秒全时间
    private String createdTimeZooe;//年月日,时分秒全时间,带时区,如:2017-04-26T14:22:27+08:00
    /**父类id**/
    private Long parentId = Constant.ZERO;
    /**顶的次数**/
    private Integer likes = 0;
    /**浏览器信息**/
    private String agent;
    /**ip**/
    private String ip;
    /**ip地址**/
    private String iplocation;
    /**评价人id**/
    private Long authorId;
    /**key**/
    private String pkey;
    /**评价来源**/
    private String referer;
    /**评价内容**/
    private String message;
    /**子父类关系id*/
    private String pids;
    /**层级ID*/
    private Integer level;
    
    public SOMessage(JsonObject jsonObj,Integer level,String pids,Long parentId,Long authorId) {
    	
    	if(null != jsonObj.get("message") && !jsonObj.get("message").isJsonNull()){
    		this.message = jsonObj.get("message").getAsString();
    	}
    	this.authorId = authorId;
		if(null != jsonObj.get("agent") && !jsonObj.get("agent").isJsonNull()){
			this.agent = jsonObj.get("agent").getAsString();
		}
		if(null != jsonObj.get("likes") && !jsonObj.get("likes").isJsonNull()){
			this.likes = jsonObj.get("likes").getAsInt();
		}
		if(null != jsonObj.get("ip") && !jsonObj.get("ip").isJsonNull()){
			this.ip = jsonObj.get("ip").getAsString();
		}
		if(null != jsonObj.get("iplocation") && !jsonObj.get("iplocation").isJsonNull()){
			this.iplocation = jsonObj.get("iplocation").getAsString();
		}
		if(null != jsonObj.get("created_at") && !jsonObj.get("created_at").isJsonNull()){
			String createdTime = jsonObj.get("created_at").getAsString();
			try {
				//时间转换
				DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); 
				Date date = df.parse(createdTime);
				this.createdTime = date; 
			} catch (Exception e) {
				this.createdTime = new Date(); 
			}
		}
		this.level = level;
		this.pids = pids;
		this.parentId = parentId;
		
	}
    public SOMessage() {
    	
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public SOMessage setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
        
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(createdTime);
        int year = calendar.get(Calendar.YEAR);
        //判断是不是今年
        if(Constant.NOW_YEAY ==year ){
        	this.createdTimeStr = DateUtil.dateToString(createdTime, "MM月dd日");
        }else{
        	this.createdTimeStr = DateUtil.dateToString(createdTime, "yyyy年MM月dd日");
        }
        this.createdYMDHMSStr = DateUtil.dateToString(createdTime, "yyyy-MM-dd ahh:mm:ss");//title 显示
        //时间转换
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX"); 
		this.createdTimeZooe = df.format(createdTime);//带时区的格式化
        return this;
    }

so_message_author 对应实体,同样getter/setter 方法不贴


/**
 * 
 * 开发公司:SOJSON在线工具 <p>
 * 版权所有:© www.sojson.com<p>
 * 博客地址:http://www.sojson.com/blog/  <p>
 * <p>
 * 
 * 评论用户实体
 * 
 * <p>
 * 
 * 区分 责任人 日期    说明<br/>
 * 创建 周柏成 2017年5月2日 19:52  <br/>
 *
 * @author zhou-baicheng
 * @email  so@sojson.com
 * @version 1.0,2017年5月2日 19:52 <br/>
 * 
 */
public class SOMessageAuthor implements Serializable{
	static final long serialVersionUID = 2147084036057204215L;
	
	/**评论人ID*/
    private Long id;
    /**第三方ID**/
    private String threadId;
    /**第三方Type*/
    private Integer threadType;
    /**头像*/
    private String avatarUrl;
    /**跳转链接*/
    private String url;
    /**用户nickname*/
    private String nickname;

    public SOMessageAuthor() {
	}
    public SOMessageAuthor(JsonObject jsonObj) {
    	JsonObject author = jsonObj.get("author").getAsJsonObject();
		String name = "SOJSON用户";
		this.nickname = name;
		if("在线工具".equals(name)){
			this.id = new Long(1);
		}
		String url = "javasciript:void(0);";
		if(null != author.get("url") && !author.get("url").isJsonNull()){
			url = author.get("url").getAsString();
		}
		this.url = url;
		String qqUid = null;
		if(null != author.get("qq_uid") && !author.get("qq_uid").isJsonNull()){
			qqUid = author.get("qq_uid").getAsString();
		}
		this.threadId= qqUid ;
		//默认头像
		String avatarUrl = "//cdn.www.sojson.com/images/default_avatar_50.gif";
		if(null != author.get("avatar_url") && !author.get("avatar_url").isJsonNull()){
			String img = author.get("avatar_url").getAsString();
			if(StringUtils.isNotBlank(img) && !StringUtils.contains(img, "duoshuo")){
				avatarUrl = img;
			}
		}
		this.avatarUrl = avatarUrl;
    }

so_message_like 对应的实体SOMessageLike ,也同样省略getter/setter 方法。

public class SOMessageLike implements Serializable{
	private static final long serialVersionUID = 86165841353511L;
	/**自增ID,没什么用*/
	private Long id;
	/**message id,关联用*/
    private Long messageId;
    /**点赞(顶) 用户id*/
    private Long userId;
    /**用户赞(顶)ip地址*/
    private String ip;
}

效果图如下,测试评论框请看这个地址:http://www.sojson.com/other/duoshuo.html



版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/222.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

关于作者
目前就职于国内某电商平台公司打杂。。
相关文章
由于多说关闭多说源码不开放Java模仿多说评论系统实现
多说迁移,Java开发模仿自主实现评论(一)
Java 实现多个级域名访问同一个Tomcat(系统)。
N多系统单点登录,实现、解决方案。四种解决方案
Shiro教程()Maven管理Shrio Jar包
Elasticsearch教程(),IK分词器安装
Java 发送Email,Java 邮件发送工具类封装
单个项目多个级域名简单实现思路
Shiro教程(十一)Shiro 控制并发登录人数限制实现,登录踢出实现
Java生成验证码合集(一)简单版
最新文章
Springboot 集成Aliyun MQ消息队列,Aliyun 消息队列配置及代码实现 7
SpringBoot 集成Spring-data-redis,redis对象序列化存储 5
天气API,全国天气 JSON API接口,可以获取十五天的天气预报 37
Springboot + Freemarker 集成配置 91
DNS查询, DNS测速检查接口,DNS测速接口 21
Mysql 并发插入、存在不插入,存在更新操作 41
SOJSON 阿里云活动达到67人,最终获得5年的1核2GB的ECS服务器使用权益 36
Java 完美解析.plist & 生成plist ,Android 解析.plist 36
Java SHA1的几种实现方式,Java SHA1 签名 56
Mac下Charles-proxy 抓包工具,iPhone 抓包演示 20
最热文章
Elasticsearch教程(四) elasticsearch head 插件安装和使用 117255
Elasticsearch教程(六) elasticsearch Client创建 75903
Elasticsearch教程(八) elasticsearch delete 删除数据(Java) 72378
Elasticsearch教程(二),IK分词器安装 70256
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 64533
Elasticsearch教程(一),全程直播(小白级别) 57880
Elasticsearch教程(五) elasticsearch Mapping的创建 55810
Elasticsearch教程(三),IK分词器安装 (极速版) 55146
Elasticsearch教程(七) elasticsearch Insert 插入数据(Java) 50434
Elasticsearch权威指南-中文.pdf,Elasticsearch 中文文档下载 43349

骚码加入我们 / 千人QQ群:259217951

入群需要5元,如果没有QQ钱包,可以先Alipay、微信,赞助然后加群主拉进。

二维码生成 来自 >> 二维码生成器

支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

正在加载... ...