技术博客

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

信息发布:soゝso 发布日期:2017-05-02 22:26 热度:943 分享到:

先什么都不多说,先看看效果,高仿多说评论已经上线,估计还是有瑕疵,不断完善中。评论链接===> :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.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



本文主题

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

¥我需要走的更远,点击我 赞助。 如果还有疑问,点击我加群,为你提供最好的解答。


工具导航地图