---------------------------------------------------------------------------------------------
[版权申明:本文系作者原创,转载请注明出处] 
文章出处: http://blog.csdn.net/sdksdk0/article/details/53634332
作者:朱培      ID:sdksdk0

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

最近十几天在做一个博客系统,因为域名服务器都闲置已久,于是乎决定合理利用起来,做个网站。系统整体架构采用分布式的系统,也是当今很多企业都在用的,基于restful风格的一套系统。从父工程开始blog-parent.这是一个pom工程,主要用来放置pom.xml文件的,这个包含了整个项目所有依赖的jar包。然后是blog-common,这个存放项目中使用到的一些工具类,也是一个pom工程。然后是blog-manager工程,这个主要是后台,包括用户操作以及管理员操作,这个项目还有一个积分商城的功能,所以商城的后台我也是放到这个manager工程里面的。这个manager是一个pom工程,然后下面的mapper和pojo以及service和web都是一个maven  module.然后除了blog-manager-web是一个war之外,剩下的三个都是jar工程。

然后前台是blog-portal,还有就是rest、search、sso、order。rest其实是给积分商城用的。search使用的是一个solr集群。因为服务器性能原因,所以我搭建的是三台tomcat的solr集群,依托zookeeper来进行管理。

sso就是单点登录系统,主要给整个系统提供登录服务的。order系统主要是给积分商城提供订单服务的。

下面来说详细内容:

一、系统后台:

后台是一个easyui的界面,非常简约,写文章的富文本编辑器我采用的是kindeditor。这个编辑器性能还是不错的,其实使用百度的ueditor富文本编辑器效果也不错,只是因为我的springmvc拦截配置的config一直不成功,于是我就换了其他的编辑器。数据提交采用的post提交。

if(title==null || title==''){alert("请输入标题!");}else if(typeId==null || typeId==''){alert("请选择博客类别!");}else if(blogTypeId==null || blogTypeId==''){alert("请选择博客类别!");}else if(content==null || content==''){alert("请输入内容!");}else{$.post("/mg/user/blog/save",{'username':username,'title':title,'typeid':typeId,'blogtypeid':blogTypeId,'content':content,'summary':summary,'contentNoTag':contentNoTag,'keyword':keyWord},function(result){if(result.success){alert("博客发布成功!");resetValue();}else{alert("博客发布失败!");}},"json"); }

编辑器有一个sync的方法;来将textarea进行同步。

var content=itemAddEditor.html();
itemAddEditor.sync();

因为这里是加入了lucene全文检索功能,所以在添加或者修改文章的时候,都需要进行索引字段处理,因为富文本编辑器存到数据库中的内容都是带html标签格式的,但是我检索肯定是不需要这些标签的,所以使用下面的方法,来把这个html标签去掉,放到contentNoTag字段,用于检索。而content就是带html标签的需要存放在数据库的内容。

var dd=content.replace(/<\/?.+?>/g,"");var contentNoTag=dd.replace(/(^\s*)|(\s*$)/g,"");//dds为得到后的内容

然后就是一个列表的查询。因为这是一个多用户的系统,所以每个用户查看的都是自己的博客信息,所以在查询的时候需要加上用户名。

对于添加博客的时候需要的一个lucene操作。

/**//*** 获取IndexWriter实例* @return* @throws Exception*//*
*/  private IndexWriter getWriter()throws Exception{dir=FSDirectory.open(Paths.get("/home/tf/work/data/lucene1/"));//dir=FSDirectory.open(Paths.get("c:\\lucene"));SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();IndexWriterConfig iwc=new IndexWriterConfig(analyzer);IndexWriter writer = null;try {writer = new IndexWriter(dir, iwc);} catch (Exception e) {writer.rollback();e.printStackTrace();}return writer;}/* *//*** 添加博客索引* @param blog*//*
*/  public void addIndex(UBlog blog)throws Exception{IndexWriter writer=getWriter();Document doc=new Document();doc.add(new StringField("id",String.valueOf(blog.getBlogid()),Field.Store.YES));doc.add(new StringField("username",String.valueOf(blog.getUsername()),Field.Store.YES));doc.add(new TextField("title",blog.getTitle(),Field.Store.YES));doc.add(new StringField("releaseDate",DateUtil.formatDate(new Date(), "yyyy-MM-dd"),Field.Store.YES));doc.add(new TextField("content",blog.getContentNoTag(),Field.Store.YES));writer.addDocument(doc);writer.close();}

而管理员就可以查看所有用户的文章,以及可以进行冻结解冻操作。

后台管理员这里还有一个积分商城,主要是用户发表博客之后又积分,积分可以兑换K币,然后K币可以兑换这个积分商城中的东西。这个商品添加之后,是不能直接在前台进行查询的,因为我对于这个商品时启用了solr搜索服务的,在我的blog-search工程中做了一个定时任务,在每天凌晨两点进行数据导入操作,系统导入完成之后,就可以在前台查看到添加的这些商品了。

   /*** 导入商品数据库到索引库*/@Scheduled(cron = "0 0 2 * * ?")   //每天凌晨两点执行@RequestMapping("/import")public void importAllItems() {System.out.println("开始执行");itemService.importAllItems();System.out.println("执行结束");}

关于整个后台来说,界面非常简约,需要的功能还是基本上齐全的。因为是分布式系统的,所以我上线的时候都是分开上线的,在上线后台之后,这个规格参数和商品列表查询一个不能及时刷新$("#itemList").datagrid("reload");我开始以为是数据量太大导致刷新慢,后来发现并不是。例如我操作了删除,其实数据库中的数据已经删除了,但是这个datagrid却没有反应,查看状态码返回的是304.然后我想到了我后台是启动了CDN缓存加速的,所以我就又跑去看CDN的配置,然后就发现问题了,于是我把列表查询的/mg/item目录的刷新时间设置为0,这样就可以及时刷新,不再是一直在缓存。这样这个问题就解决了。

通过这个事情我知道,在本地的localhost操作和上线真的是不同的。在上线过程还遇到了很多在本地操作没有发生的事情,在本地都没有什么问题,一到云服务器上部署,马上问题就来了。哎!真是个磨人的小妖精。

二、前台

前台的话基本上也就这样了,因为审美水平问题,只能做到这个样子了,毕竟没有美工,毕竟我是做系统架构和数据处理数据分析的,哎,看来还是有不足之处啊。大家就将就着看吧,哈哈。 http://www.tianfang1314.cn/

前台的这个博客文章我都加入到了redis缓存中,所以访问速度理论上还是提升了的。前台页面在CDN缓存设置的是一分钟,所以后台增删改什么的理论上是要过一分钟之后,前台才会更新的。

关于前台的lucene搜索就是:

/**//*** 查询博客信息* @param q 查询关键字* @return* @throws Exception*//*
*/  public List<UBlog> searchBlog(String q)throws Exception{dir=FSDirectory.open(Paths.get("/home/tf/work/data/lucene1/"));IndexReader reader = DirectoryReader.open(dir);IndexSearcher is=new IndexSearcher(reader);BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();QueryParser parser=new QueryParser("title",analyzer);Query query=parser.parse(q);QueryParser parser2=new QueryParser("content",analyzer);Query query2=parser2.parse(q);booleanQuery.add(query,BooleanClause.Occur.SHOULD);booleanQuery.add(query2,BooleanClause.Occur.SHOULD);TopDocs hits=is.search(booleanQuery.build(), 100);QueryScorer scorer=new QueryScorer(query);  Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);  SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");Highlighter highlighter=new Highlighter(simpleHTMLFormatter, scorer);highlighter.setTextFragmenter(fragmenter);  List<UBlog> blogList=new LinkedList<UBlog>();for(ScoreDoc scoreDoc:hits.scoreDocs){Document doc=is.doc(scoreDoc.doc);UBlog blog=new UBlog();blog.setBlogid(doc.get(("id")));blog.setUsername(doc.get("username"));blog.setReleaseDateStr(doc.get(("releaseDate")));String title=doc.get("title");String content=StringEscapeUtils.escapeHtml(doc.get("content"));if(title!=null){TokenStream tokenStream = analyzer.tokenStream("title", new StringReader(title));String hTitle=highlighter.getBestFragment(tokenStream, title);if(StringUtil.isEmpty(hTitle)){blog.setTitle(title);}else{blog.setTitle(hTitle);                  }}if(content!=null){TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(content)); String hContent=highlighter.getBestFragment(tokenStream, content);if(StringUtil.isEmpty(hContent)){if(content.length()<=200){blog.setContent(content);}else{blog.setContent(content.substring(0, 200));                        }}else{blog.setContent(hContent);                   }}blogList.add(blog);}return blogList;}

效果还是不错的,大家可以去试一下,文末提供访问网址。说到这个文章啊,遇到最头疼的问题就是编码问题了,因为页面展示是一种,然后我mysql数据库的编码,还有redis中存放的文章的编码。添加缓存的时候又各种进行转换。都快转晕了,哈哈,当然最终还是解决了,挺开心的。

blog.setContent(new String(blog.getContent().getBytes("iso-8859-1"),"utf-8"));

商品搜索这边就是调用者blog-search的服务就可以了。关于这个地方的细节我就不再重复说了,今天只谈架构。

三、Nginx

因为这个系统前后十二个工程,其中mg做为后台,portal做的前台,以及前面说到的各种。所以我需要一个nginx来处理,主要就是配置端口与域名的映射。在nginx中进行配置即可。当然,也是可以直接使用tomcat热部署直接传到服务器中的tomcat中。当然如果用的是其他中间件服务器的话配置也是类似的。就是域名端口号说明的。(为了我服务器的安全,下面配置的端口号我修改了与我真实上线不同的端口号了),你也可以按自己的实际情况配置。总之还是非常实用和简单的。

upstream manager.tianfang1314.cn{server  139.199.158.214:9100;}upstream rest.tianfang1314.cn{server  139.199.158.214:9101;}upstream search.tianfang1314.cn{server  139.199.158.214:9101;}upstream sso.tianfang1314.cn{server  139.199.158.214:9103;}
server {listen       80;server_name  manager.tianfang1314.cn;location / {proxy_pass   http://manager.tianfang1314.cn;index  index.html index.htm;}}server {listen       80;server_name  rest.tianfang1314.cn;location / {proxy_pass   http://rest.tianfang1314.cn;index  index.html index.htm;}}server {listen       80;server_name  search.tianfang1314.cn;location / {proxy_pass   http://search.tianfang1314.cn;index  index.html index.htm;}}server {listen       80;server_name  sso.tianfang1314.cn;location / {proxy_pass   http://sso.tianfang1314.cn;index  index.html index.htm;}}

四、开发中遇到的问题

我遇到最烦人的问题就是这个图片上传的问题,我本来是使用的FTP进行图片上传的。然后这个磨人的小妖精在本地上传的时候没有任何问题,我一部署到服务器,完了,完全post不上去了,折腾的够呛,一直是什么network什么什么的错误,简直气炸!我后来慢慢的排查问题,从文件大小限制,nginx配置,cdn缓存配置,服务器权限,还从朋友那里在接了一台tomcat来测试,发现依然是这个问题。折腾了一天。然后我就放弃治疗。

Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "http://manager.tianfang1314.cn" from accessing a frame with origin "null".  The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match.

当然,最后我换了一种方案,本来这个图片是全部要存放到我的ftp图片服务器中的。既然解决不了怎么办呢,这个图片上传的功能是必须要的啊,于是乎,我突然发现了COS对象存储服务。简直发现宝有木有。开始看文档感觉挺复杂的,后来自己折腾了一下,将这个cos的官方代码于我的ftp工具类的代码进行了整合,哎呦喂,居然成功了,1个小时就搞定了。在这一篇博客中介绍如何使用腾讯云的COS对象存储服务。

网站的访问网址就是: http://www.tianfang1314.cn/

或者http://blog.tianfang1314.cn/

谈一谈CloudBlog的系统架构相关推荐

  1. 【ZZ】浅谈大型web系统架构 | 菜鸟教程

    浅谈大型web系统架构 http://www.runoob.com/w3cnote/large-scale-web-system-architecture.html 转载于:https://www.c ...

  2. [原创] 浅谈ETL系统架构如何测试?

    [原创] 浅谈ETL系统架构如何测试? 来新公司已入职3个月时间,由于公司所处于互联网基金行业,基金天然固有特点,基金业务复杂,基金数据信息众多,基金经理众多等,所以大家可想一下,基民要想赚钱真不容易 ...

  3. 阿里资深系统架构师九峰谈云计算

    为什么80%的码农都做不了架构师?>>>    阿里资深系统架构师九峰谈云计算 被誉为改写IT面貌的"第三次IT革命"的主角云计算,已经从最初的"萌动& ...

  4. 浅谈秒杀系统架构设计

    秒杀是电子商务网站常见的一种营销手段. 原则 不要整个系统宕机. 即使系统故障,也不要将错误数据展示出来. 尽量保持公平公正. 实现效果 秒杀开始前,抢购按钮为活动未开始. 秒杀开始时,抢购按钮可以点 ...

  5. 回溯法 批处理作业调度_不懂调度系统架构,就不要谈银行数据仓库

    调度系统是数据仓库的重要组成部分,也是每个银行或公司一个基础软件或服务,需要在全行或全公司层面进行规划,在全行层面统一调度工具和规范,由于数据类系统调度作业较多,交易类系统批量优先级高,为不互相影响可 ...

  6. 浅谈大型web系统架构

    动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应用系统通常与数据库系统. ...

  7. 浅谈系统架构设计-从架构设计原理、架构设计原则、架构设计方法展开

    我们工作中一直强调要做架构设计.系分,最近前端同学在追求前端质量提升的时候,也在进行架构设计.前端系分的推广,那到底什么是架构设计和系分?该怎么做架构设计和系分?本文尝试对架构设计进行全面的介绍和分享 ...

  8. 系统架构师谈企业应用架构之业务逻辑层

    一.上章回顾 上章我们主要讲述了系统设计规范与原则中的具体原则与规范及如何实现满足规范的设计,我们也讲述了通过分离功能点的方式来实现,而在软件开发过程中的具体实现方式简单的分为面向过程与面向对象的开发 ...

  9. 互联网项目系统架构经验浅谈

    一.如此架构设计构想的起因 1."互联网+"这个概念之后,政府部门.民营企业等各行各业似乎忽然都"醒了",每个单位都发现自己迫切需要建设各类信息化系统,&quo ...

  10. Zilliz 合伙人、系统架构师郭人通出席GOTC 2021专题论坛,谈向量数据库的开发挑战...

    AI 正在引领人类的下一次工业革命,成为支撑数字经济的基本工具组件. 7月9-10日,由开放原子开源基金会与 Linux 基金会联合开源中国社区共同发起的首届"GOTC 全球开源技术峰会&q ...

最新文章

  1. [Android] Bitmap OOM解决办法二
  2. ajax中return不生效
  3. SNF平台从sql server兼容oracle的处理方式和开发方式
  4. linux_base-f10-10_7 linuxulator is not (kld)loaded
  5. java xml 序列化_java-序列化为XML时忽略父类
  6. 阿里巴巴中间件在 Serverless 技术领域的探索
  7. Linux--iptables常用命令
  8. xhell启动mysql_xshell怎么搭建mysql
  9. linux下find用法 find -name *.so -exec ll {} \;
  10. 敏捷转型历程 - Sprint3 一团糟的演示会
  11. android封装全局调用的toast_自定义Toast,解决系统Toast存在的问题
  12. for的循环在php那边使用,for循环如何在php怎么中使用
  13. LaserJet 5000 及 5100 系列打印机出现 pcl xl error 怎么办
  14. ftp搭建发布到外网踩坑记
  15. Python之使用代理服务器访问网页
  16. 台式计算机电源接线图,​台式机硬盘电源线接法【图解】
  17. 管理员不让我使用计算机管理,用u盘禁用软件教你实现电脑禁止使用u盘、管理员禁止使用u盘...
  18. Elastix 设置呼叫转移
  19. [原]解密Airbnb 自助BI神器:Superset 颠覆 Tableau
  20. 解决:AWVS(Acunetix)激活频繁失效(仅供学习)

热门文章

  1. mysql卸载报错2503_Win10系统卸载Skype软件报错2503的解决方法
  2. python输出数字三角形_python 数字三角形
  3. 笔记本dns服务器怎么修改,笔记本电脑DNS怎么设置
  4. Mac 输入法自动切换,代码编辑器中文状态下使用英文标点
  5. cubic算法优化_CUBIC拥塞拥塞控制算法
  6. 完美商业计划书全攻略
  7. allegro 尺寸标注操作未到板边的处理
  8. matlab中断概率仿真,使用Matlab进行误比特率仿真
  9. html 动态导航菜单,导航菜单,css3,javascript,响应式菜单,html,css
  10. Intelij的IDEA启动报错!parent directory is read-only or the user lacks necessary permissions