上一个电商项目的反思

从去年实习到今年转正,陆陆续续接触了大概四个项目。有电商类,互联网保险类,也经历过管理系统。幸运的是,这些项目都是从零开始,避免了让我去维护不堪入目的老旧系统。而这么多项目中令我印象最深刻的,就要属上一个电商项目了。这也是我接触到的真正意义的第一个微服务项目,到今天回首去看曾经的这个项目,有很多突破性地尝试,同时不可避免地也踩入了一些坑点,毕竟摸着石头过河。今天想聊聊我对上一个电商项目的反思。

项目简介

准确的说是一个第三方的电商项目,商品来源是由主流电商的 http 接口提供(目前接入了京东,苏宁),打造我们自己的商城体系。使用的技术包括 springboot,jpa,rpc 框架使用的是 motan,数据库使用的是 oracle,基本都还算是主流的技术。


浅析 Spring 中的事件驱动机制

今天来简单地聊聊事件驱动,其实写这篇文章挺令我挺苦恼的,因为事件驱动这个名词,我没有找到很好的定性解释,担心自己的表述有误,而说到事件驱动可能立刻联想到如此众多的概念:观察者模式,发布订阅模式,消息队列 MQ,消息驱动,事件,EventSourcing… 为了不产生歧义,笔者把自己所了解的这些模棱两可的概念都列了出来,再开始今天的分享。

  • 在设计模式中,观察者模式可以算得上是一个非常经典的行为型设计模式,猫叫了,主人醒了,老鼠跑了,这一经典的例子,是事件驱动模型在设计层面的体现。
  • 另一模式,发布订阅模式往往被人们等同于观察者模式,但我的理解是两者唯一区别,是发布订阅模式需要有一个调度中心,而观察者模式不需要,例如观察者的列表可以直接由被观察者维护。不过两者即使被混用,互相替代,通常不影响表达。
  • MQ,中间件级别的消息队列(e.g. ActiveMQ,RabbitMQ),可以认为是发布订阅模式的一个具体体现。事件驱动 -> 发布订阅 ->MQ,从抽象到具体。
  • java 和 spring 中都拥有 Event 的抽象,分别代表了语言级别和三方框架级别对事件的支持。
  • EventSourcing 这个概念就要关联到领域驱动设计,DDD 对事件驱动也是非常地青睐,领域对象的状态完全是由事件驱动来控制,由其衍生出了 CQRS 架构,具体实现框架有 AxonFramework。
  • Nginx 可以作为高性能的应用服务器(e.g. openResty),以及 Nodejs 事件驱动的特性,这些也是都是事件驱动的体现。

从 Feign 使用注意点到 RESTFUL 接口设计规范

最近项目中大量使用了 Spring Cloud Feign 来对接 http 接口,踩了不少坑,也产生了一些对 RESTFUL 接口设计的想法,特此一篇记录下。

[TOC]

SpringMVC 的请求参数绑定机制

了解 Feign 历史的朋友会知道,Feign 本身是 Netflix 的产品,Spring Cloud Feign 是在原生 Feign 的基础上进行了封装,引入了大量的 SpringMVC 注解支持,这一方面使得其更容易被广大的 Spring 使用者开箱即用,但也产生了不小的混淆作用。所以在使用 Spring Cloud Feign 之前,笔者先介绍一下 SpringMVC 的一个入参机制。预设一个 RestController,在本地的 8080 端口启动一个应用,用于接收 http 请求。


Re:从零开始的 Spring Session(二)

上一篇文章介绍了一些 Session 和 Cookie 的基础知识,这篇文章开始正式介绍 Spring Session 是如何对传统的 Session 进行改造的。官网这么介绍 Spring Session:

Spring Session provides an API and implementations for managing a user’s session information. It also provides transparent integration with:

  • HttpSession - allows replacing the HttpSession in an application container (i.e. Tomcat) neutral way. Additional features include:
    • Clustered Sessions - Spring Session makes it trivial to support clustered sessions without being tied to an application container specific solution.
    • Multiple Browser Sessions - Spring Session supports managing multiple users’ sessions in a single browser instance (i.e. multiple authenticated accounts similar to Google).
    • RESTful APIs - Spring Session allows providing session ids in headers to work with RESTful APIs
  • WebSocket - provides the ability to keep the HttpSession alive when receiving WebSocket messages

其具体的特性非常之多,具体的内容可以从文档中了解到,笔者做一点自己的总结,Spring Session 的特性包括但不限于以下:

  • 使用 GemFire 来构建 C/S 架构的 httpSession(不关注)
  • 使用第三方仓储来实现集群 session 管理,也就是常说的分布式 session 容器,替换应用容器(如 tomcat 的 session 容器)。仓储的实现,Spring Session 提供了三个实现(redis,mongodb,jdbc),其中 redis 使我们最常用的。程序的实现,使用 AOP 技术,几乎可以做到透明化地替换。(核心)
  • 可以非常方便的扩展 Cookie 和自定义 Session 相关的 Listener,Filter。
  • 可以很方便的与 Spring Security 集成,增加诸如 findSessionsByUserName,rememberMe,限制同一个账号可以同时在线的 Session 数(如设置成 1,即可达到把前一次登录顶掉的效果)等等

介绍完特性,下面开始一步步集成 Spring Session


Re:从零开始的 Spring Session(一)

Session 和 Cookie 这两个概念,在学习 java web 开发之初,大多数人就已经接触过了。最近在研究跨域单点登录的实现时,发现对于 Session 和 Cookie 的了解,并不是很深入,所以打算写两篇文章记录一下自己的理解。在我们的应用集成 Spring Session 之前,先补充一点 Session 和 Cookie 的关键知识。

由于 http 协议是无状态的协议,为了能够记住请求的状态,于是引入了 Session 和 Cookie 的机制。我们应该有一个很明确的概念,那就是 Session 是存在于服务器端的,在单体式应用中,他是由 tomcat 管理的,存在于 tomcat 的内存中,当我们为了解决分布式场景中的 session 共享问题时,引入了 redis,其共享内存,以及支持 key 自动过期的特性,非常契合 session 的特性,我们在企业开发中最常用的也就是这种模式。但是只要你愿意,也可以选择存储在 JDBC,Mongo 中,这些,spring 都提供了默认的实现,在大多数情况下,我们只需要引入配置即可。而 Cookie 则是存在于客户端,更方便理解的说法,可以说存在于浏览器。Cookie 并不常用,至少在我不长的 web 开发生涯中,并没有什么场景需要我过多的关注 Cookie。http 协议允许从服务器返回 Response 时携带一些 Cookie,并且同一个域下对 Cookie 的数量有所限制,之前说过 Session 的持久化依赖于服务端的策略,而 Cookie 的持久化则是依赖于本地文件。虽然说 Cookie 并不常用,但是有一类特殊的 Cookie 却是我们需要额外关注的,那便是与 Session 相关的 sessionId,他是真正维系客户端和服务端的桥梁。


XML 与 javabean 的转换

XML 可以说是一种被时代淘汰的数据传输格式,毕竟相比较 JSON,其语法,表现形式,以及第三方类库的支持,都要略逊一筹,但最近在对接一些老接口时,主要还是以 XML 为主,而翻阅相关的文档以及博客,没看到很好的文章介绍如何使用 xml 进行数据传输,所以简单写下此文,做一下记录。内心多多少少还是会抵制对接如此老旧的接口,不过生活还是要继续。

Code First

先上一段代码,展示一下如何封装,讲解放到后面

一个典型的对接方提供的 XML 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ORDER>
<ORDER_NO>10086</ORDER_NO>
<TOTAL_PRICE>3.14</TOTAL_PRICE>
<CREATE_TIME>2017-08-26 03:39:30</CREATE_TIME>
<ORDER_ITEMS>
<ORDER_ITEM>
<GOODS_NAME> 德芙 </GOODS_NAME>
<NUM>3</NUM>
</ORDER_ITEM>
<ORDER_ITEM>
<GOODS_NAME> 旺仔 </GOODS_NAME>
<NUM>10</NUM>
</ORDER_ITEM>
</ORDER_ITEMS>
</ORDER>

而我们要对应的实体类,则应当如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@XmlRootElement(name = "ORDER")// <1>
@XmlAccessorType(XmlAccessType.FIELD)// <1>
public class Order {

@XmlElement(name = "ORDER_NO")// <1>
private String orderNo;

@XmlElement(name = "TOTAL_PRICE")
private BigDecimal totalPrice;

@XmlElement(name = "CREATE_TIME")
@XmlJavaTypeAdapter(DateAdapter.class) // <2>
private Date createTime;

@XmlElementWrapper(name = "ORDER_ITEMS") // <3>
@XmlElement(name = "ORDER_ITEM")
private List<OrderItem> orderItems;

}
1
2
3
4
5
6
7
8
9
10
@XmlAccessorType(XmlAccessType.FIELD)
public class OrderItem {

@XmlElement(name = "GOODS_NAME")
private String goodsName;

@XmlElement(name = "NUM")
private Integer num;

}

我举的这个示例基本包含一般情况下所有可能出现的需求

<1> 常用注解 XmlRootElement,XmlAccessorType,XmlElement

<2> 日期转换的适配器注解

<3> 如何在 XML 中设置集合

在介绍这三点之前,先给出转换的工具类


sinosoft 代码规范

介绍

本文档主要针对我们项目内部正在使用的框架,以及代码审查发现的一些共性问题提出一些开发规范。

JavaBean 规范

1 驼峰命名法【强制】

2 布尔类型规范【强制】
【说明】所有的布尔类型不允许以 is 开头,否则会导致部分序列化,hibernate 框架出现解析异常。
【反例】
原来项目的 BaseDomain 中标记逻辑删除的字段, 在部分场景下会出现问题


博客搬家

陆陆续续,写博客已经写了有 4 年多了,之前一直在 CSDN 维护博客(博客旧址),最近有了点空余时间,使用 hexo 搭了这个博客,的确比 CSDN 清爽多了,首先感谢 @程序猿 DD 推荐的 icarus 模板,国人开发的一个 hexo 模板,插件支持可能不是很完善,但是样式非常让人喜欢。

作为一个前端弱渣,搭建博客的过程还是遇到了不少的困难。原先是打算直接使用 github 个人主页作为博客地址,hexo 对 git 有很好的支持,源代码和博客静态页面都托管在了 github,master 分支放静态页面,hexo 分支放源文件。可惜的是国内坑爹的网速,github.io 的访问速度不尽如人意(github.com 倒还好),于是在宇泽学妹 @ntzyz 的帮助下,搞了 github 的 hook,本地提交到 github 时,代理服务器自动向 master 分支拉取页面,同时设置反向代理和 https。由于 hexo 是静态文件搭建的博客,这种方式可以说是非常合适的。所以,国内的朋友浏览本博客可以直接访问 https://www.cnkirito.moe,如果有国外代理的朋友可以直接访问我的 github 个人主页 https://lexburner.github.io

目前博客功能还不算完善,缺少评论,分享,和一些小插件,以后逐渐完善,不过不影响主要功能。以后这儿就作为我主要更新博客的地方了!


Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×