订单系统服务端和客户端工程搭建、利用拦截器实现登录功能及订单确认页面展示、生成订单

订单系统服务端和客户端工程搭建

首先我们还是先看一眼淘淘商城的系统架构,如下图所示,可以看到订单模块是单独的模块,有服务端还有客户端,服务端负责存储订单,客户端负责展示订单。

下面我们便来搭建订单服务,点击File---->New----->Other…如下图所示。

选择"Maven Project",然后点击"Next",如下图所示。

勾选最上面的那个复选框,然后点击"Next",如下图所示。

我们要先创建聚合工程taoao-order,后面再创建属于该聚合工程的两个模块taotao-order-interface和taotao-order-service,之所以不建dao模块是因为我们逆向生成的代码便可以直接使用,因此不用单独创建dao模块。

下面我们配置taotao-order的pom.xml文件,我们可以参考taotao-content工程的pom.xml文件,如下图所示。

下面我们再来新建taotao-order聚合工程的两个模块,首先创建taotao-order-interface模块,在taotao-order工程上右键,在右键菜单中点击"New",在子菜单中点击"Other…",如下图所示。

选择"Maven Module",然后点击"Next",如下图所示。

勾选最上面的复选框,在Module Name一栏输入"taotao-order-interface",然后点击"Next"。

打包方式默认就是jar,我们不用动,直接点击“Finish”,如下图所示。

下面我们便配置taotao-order-interface的pom.xml文件,我们可以参考taotao-content-interface工程的pom.xml文件,如下图所示。

下面我们再创建taotao-order-service模块,还是在taotao-order工程上右键---->New----->Other…,如下图所示。

选择"Maven Module",然后点击"Next",如下图所示。

勾选最上方的复选框,在Module Name一栏输入"taotao-order-service",然后点击"Next",如下图所示。

打包方式选择war,然后点击"Finish"。

下面我们配置taotao-order-service的pom.xml文件,我们可以参考taotao-content-service工程的pom.xml文件,将原来依赖的taotao-content-interface修改为taotao-order-interface,另外将后面的redis的依赖去掉。

配好后,taotao-order-service工程的pom.xml文件的内容如下:

下面我们将taotao-content-service工程src/main/resources目录下的文件夹拷贝过来mybatis目录下配置文件不用动,properties目录下的db.properties文件不用动,将resource.properties文件清空,并且设置该文件的编码格式为utf-8。

下面我们修改spring目录下的文件,applicationContext-dao.xml文件我们不用动,删掉applicationContext-jedis.xml文件,然后修改applicationContext-service.xml文件,扫描包修改为com.taotao.order.service,然后我们在taotao-order-interface工程的src/main/java目录下新建包com.taotao.order.service,然后在taotao-order-service工程的src/main/java目录下新建一个com.taotao.order.service.impl包。dubbo服务的名称修改为"taotao-order",修改dubbo暴露的服务端口,前面已经用到8083了,因此这里改为8084,声明要暴露的接口这块,由于我们还没有写接口,暂且保留原来的一个配置,并注释掉,这样后面我们暴露服务的时候只需要稍微修改下就好了。

下面我们再修改下applicationContext-trans.xml文件,订单模块对事务要求非常高,将切面修改为"com.taotao.order.service"。

下面我们再把taotao-content-service工程下的WEB-INF目录直接拷贝到taotao-order-service工程的webapp目录下,修改下的值为"taotao-order"。这样我们的服务端工程便搭建完了。

下面我们来搭建订单表现层工程taotao-order-web,第一步还是File----->New------>Other…,如下图所示。

第二步还是选择"Maven Project",然后点击"Next"。

第三步还是勾选最上面的那个复选框,然后点击"Next"。

第四步如下图,打包方式选择"war",然后点击"Finish"。

下面我们修改taotao-order-web工程的pom.xml文件,我们可以参考taotao-port-web工程的pom.xml文件,将原来依赖的taotao-content-interface修改为taotao-order-interface,然后将最下面tomcat插件的端口号修改为8091。

修改后taotao-order-web工程的pom.xml文件内容如下:

然后我们将taotao-portal-web工程src/main/resources目录下的文件夹拷贝过来,接着我们将resource目录下的resource.properties文件内容清空,并将该文件的编码格式设置为utf-8。

下面我们修改springmvc.xml文件,扫描包修改为com.taotao.order.controller,并且在taotao-order-web工程的src/main/java目录下新建这个包,引用的dubbo服务名称修改为taotao-order-web,将原来引用的服务先注释掉,后面需要用的时候可以稍微修改下即可。

最后我们把taotao-portal-web工程的web.xml文件复制过来,但前提是先在taotao-order-web工程的webapp目录下新建一个WEB-INF目录,把web.xml文件复制到WEB-INF目录下。将所有taotao-portal-web都替换为taotao-order-web即可。

这样,我们的服务端和客户端工程便都搭建好了。

利用拦截器实现登录功能及订单确认页面展示

我们上节课一起搭建了订单的服务工程和web工程,我们参考京东可以知道,京东在没有登录时就可以使用购物车,但是当要真正付款的时候,一定是要求登录的。也就是说由购物车列表页面直接跳转到登录页面去登录。这显然用到了拦截器的功能,这节课我们便一起实现登录功能。

下图便是购物车列表页面,我们点击"去结算",如果当前用户还没登录,是必须要先登录的。

下面我们便来写拦截器,拦截器是要实现HandlerInterceptor的,我们在taotao-order-web工程的src/main/java目录下新建一个包com.taotao.order.interceptor并在该包下新建LoginInterceptor拦截器(实现HandlerInterceptor)

可以看到,我们在代码中用到了两个常量,常量我们要定义在配置文件当中
preHandle方法的第3步通过token取用户信息,显然用到了SSO服务的接口,因此我们需要在taotao-order-web工程依赖taotao-sso-interface工程,如下图所示。

光依赖taotao-sso-interface还不行,我们还得在springmvc.xml文件中引用taotao-sso-service发布的dubbo服务,另外我们写的拦截器Spring是不知道的,我们得告诉Spring我们写了这个拦截器,于是需要在springmvc.xml文件中配置下拦截器。

我们是要由购物车列表页面访问订单页面时触发拦截器的,因此我们要先处理购物车列表页面,如下图所示,我给大家提供的静态页面这里已经改过了,不用修改。

由于要访问订单页面,因此我们需要把订单的静态资源放到taotao-order-web工程下,

我们要访问的订单页面是order-cart.jsp页面,如下图所示,这个页面中"cartList"是Controller返回的购物车列表,cart的属性一定要正确,我给大家的静态资源文件已经修改好了,可以直接使用。

我们需要在taotao-order-web写一个Controller来响应购物车列表请求访问订单页面的请求

上面代码中用到了常量CART_KEY,因此我们需要在配置文件中配置下这个常量

下面我们先来测试下拦截器是否好使,我们要启动taotao-order-web工程,但是要先将taotao-order聚合工程打包到本地maven仓库,方法是在taotao-order工程上右键----->Run As------>Maven install

我们启动taotao-order-web工程,在taotao-order-web工程上右键------>Run As----->Maven build在弹出的对话框中的Goals一栏输入"clean tomcat7:run

启动成功后,我们再点击本篇博客第一张图的"去结算",就可以看到,页面跳转到了登录页面,如下图所示。说明我们的拦截器没问题

我们输入用户名和密码进行登录,发现登录到淘淘商城首页了,这不是我们想要去的页面,应该到订单确认页面页面才对。

登录有没有成功在login.jsp当中有判断,如下图所示,可以看到,js首先会去尝试获取从Controller端传过来的回调地址,如果取到了回调地址,那么登录成功后会跳转到回调地址,如果没有取到回调地址,那么登录成功后直接访问的便是淘淘商城首页,在上图中之所以我登录成功后访问到的是淘淘商城首页就是因为我们没有在PageController 当中添加回调地址。

下面我们到taotao-sso-web工程的PageController中简单做下修改,如下图所示,我们在showLogin方法中添加了两个参数,一个是回调地址url,另一个是用来给jsp页面添加属性的Model,回调地址url也不是凭空来的,它是由拦截器重定向时就指定好的。

既然我们修改了taotao–sso-web工程,下面我们便重启taotao-sso-web工程,重启后,我们重新来测试一下,如果你是刚登录的话,cookie中已经有你的登录信息而且token还没过期,要想达到用户未登录的情况,有两种方法,一是删除cookie中的TT_TOKEN,如下图所示,另一种方法就是等,等30分钟,30分钟后token过期。显然,我们删除cookie中的TT_TOKEN比较靠谱。

删除了cookie中的token或token过期后,我们还是从购物车列表页面(本篇博客第一张图)点击"去结算",还是会让我们登录,登录后会提示登录成功,点击"确定"后,我们看到的是下图所示页面,而不再是淘淘商城首页了。下图便是订单确认页面。

但是当前这个页面头部还是显示的是未登录状态,我们参考单点登录系统的代码,在taotao-order-web工程的js目录下找到base-v1.js,打开它修改最上面的两个方法。

修改的代码如下,这样从订单确认页面便可以点击"登录"或"注册"跳转到相应的页面。

我们再修改下js目录下的taotao.js文件,其实这个文件我们只需要将端口修改为8088就可以了。

下面我们重启taotao-order-web工程,重启后,我们刷新订单确认页面,便可以看到头部有用户信息了。

生成订单

第一部分:订单数据库分析

我们先来看下tb_order表,如下图所示,可以看到,

主键order_id是字符串类型,不是自增长的,因此我们需要自己生成订单编号,我们平时使用京东、天猫等购物网站,发现人家的订单号都是用数字组成的,我们也使用数字作为订单号,但是怎样才能使订单号不重复呢?用时间加随机数的方案生成的订单其实还是可能会重复的,当同一时刻生成的订单越多越有可能出现订单号一样的情况,因此我们不能使用这种方案。比较好的方案是什么呢?是用redis的incr方法,由于redis是单线程的,因此无论多少个线程共同访问也不会出现订单编号一样的情况。

payment字段是实付金额,需要从前台传过来,保留小数点后2位,
payment_type是支付类型,分为在线支付和货到付款,也需要从前台页面传过来,
post_free字段是邮费,邮费得由前台传过来,因为很多电商都搞活动,买够多少钱的东西就免邮费,因此邮费是动态变化的。
status字段是订单状态,订单状态我们暂且定义了6种状态,未付款、已付款、未发货、已发货、交易成功、交易关闭。create_time字段是订单创建时间,这没什么可说的,
update_time字段是订单更新时间,这个通常是订单状态发生了变化,
payment_time字段是付款时间,
consign_time字段是发货时间,
end_time字段是交易完成时间,这个通常是用户点确认收货的时间,交易关闭时间则是该订单的所有流程都走完后的时间。
shipping_name字段是物流名称,即用的谁家的快递。
shipping_code字段是物流单号,这个不用废话。
user_id字段当然是指购买者ID。
buyer_message字段是指买家留言,
buyer_nick字段指买家昵称。
buyer_rate字段记录买家是否已经评价。
表中还可以看到create_time、buyer_nick、status、payment_type四个字段由key修饰,说明为这四个字段建立了索引。

可以看到订单表中并没有购买商品详情信息,那么商品详情信息在哪儿存放呢?它被存放到了tb_order_item表中,主键id字段也是个字符串,我们也需要为其生成主键,不过我倒是觉得,如果id用Long类型并且主键自增长会更好点。

接着我们看tb_order_shipping,这张表存放的是用户的收货信息,包括收货人姓名、固定电话、移动电话、省、市、区/县、街道门牌号、邮政编码,而且收货人信息与订单是一对一的,因此收货地址表的主键是order_id。

第二部分:订单生成页面分析
生成订单是在订单确认页面进行的,如下图所示,可以看到"提交订单"按钮。

我们找到这个页面对应的jsp文件,那就是order-cart.jsp,搜索"提交订单",可以看到如下图所示搜索结果,可以看到这是个button按钮,该按钮的onclick事件中使用id选择器来得到表单,并且将该表单提交。

那么,表单在哪儿呢?我们搜索"orderForm",如下图所示,可以看到这个表单所有的标签都是隐藏的,是不会被用户看到的,用户看到的只是表单下面展示的信息(这些信息只是做展示用,不会被提交,真正提交的是被隐藏的表单)。表单要提交的话,我们一般用pojo来接收比较合适,那么这个表单我们应该用什么样的pojo来接收呢?

我们分析下上图的表单,这个表单中包含了三张表的信息,其中便是tb_order表中的付款类型字段,这里默认是1了,<c:forEach>遍历的是购物车列表,var="cart"表示单个购物车对象,varStatus="status"的用法如下所示

varStatus属性可以方便我们实现一些与行数相关的功能,如:奇数行、偶数行差异;最后一行特殊处理等等。先就varStatus属性常用参数总结下:
${status.index} 输出行号,从0开始。
${status.count} 输出行号,从1开始。
${status.current} 当前这次迭代的(集合中的)项
${status.first} 判断当前项是否为集合中的第一项,返回值为true或false
${status.last} 判断当前项是否为集合中的最后一项,返回值为true或false
begin、end、step分别表示:起始序号,结束序号,跳跃步伐。

可以看到我们这里用到的便是其行号功能,而且是从0开始,orderItems是个集合,该集合通过索引号获取它的对象,然后将购物车对象的对应属性赋给orderItems集合中当前索引号下的对象的这个属性,totalPrice是将购物车里每款商品的总价格相加,就是整个订单的总金额。forEach里面的属性值都是tb_order_item表中的字段。forEach之后就是payment字段,该字段也是tb_order表里面的字段,表示付款金额,我们看到了给payment赋的值是value="${totalPrice/100 },这里之所以要除100是由于我们的tb_order_item表中定义的商品单价便是整数,这个整数是以分为单位乘以100的,这样两位小数的金额比如11.11元便在数据库中存成了1111,当然了,数据库中存储的金额单位便是分了,不再是元了。数据库中虽然存储的是以分为单位的价格,但是我们展示在页面的价格肯定是以元为单位的,因此我们需要让totalPrice/100,这才是以元为单位的金额。接着,下面这几句代码意思比较明显,显然存放的是收货人地址信息,用到的类是逆向生成的TbOrderShipping类。

综合以上情况,我们来写个pojo类包含这些表单信息,那么我们这个pojo应该放到哪儿比较合适呢?我们不能把它放到taotao-common当中,因为我们的taotao-order工程已经依赖了taotao-common工程了,如果taotao-common工程现在再依赖taotao-order,那么便成了相互依赖了,这是断不可行的。我们还想让它尽可能的共用,把它放到taotao-order-interface工程比较合适,因为taotao-order工程及taotao-order-web工程都依赖taotao-order-interface,因此把pojo写到taotao-order-interface工程比较合适。

pojo类如下图所示,这里用到了一个技巧,那就是继承了TbOrder类,这样OrderInfo便直接拥有了TbOrder的属性。为了让该pojo在网络中传输,我们需要让它实现序列化接口。

第三部分:生成订单
首先我们需要在taotao-order-interface工程新建一个接口类并在该接口类中添加一个接口,如下图所示。

下面我们在taotao-order-service工程的com.taotao.order.service.impl包下新建OrderService接口的实现类

既然用到了redis,我们便要添加对redis的依赖、redis的配置文件以及redis的接口和实现类,首先我们在taotao-order-service工程添加对redis的依赖

下面我们还需要redis的配置文件,我们可以从taotao-manager-service工程的spring目录下复制一份过来,如下图所示,由于初始化Spring容器时以applicationContext-*.xml为条件了,因此凡是以"applicationContext-“”开头的都会被装入容器中。

下面我们从taotao-content-interface工程中复制com.taotao.jedis.service目录到taotao-order-interface工程的src/main/java目录下,然后把taotao-content-service工程的com.taotao.jedisservice.impl包复制到taotao-order-service工程的src/main/java目录下

代码中还用到了常量,我们把常量放到配置文件中

配置文件有了,但是我们要确认Spring加载了该配置文件,我们查看applicationContext-dao.xml文件,发现加载了properties目录下所有以.properties文件结尾的配置文件。所以自然而然resource.properties文件也被加载了。

第四部分:订单生成表现层
既然服务端写好了,我们便要发布服务,我们在applicationContext-service.xml文件中发布,如下图所示

下面便是在taotao-order-web工程引用dubbo服务

接着我们在taotao-order-web工程的OrderController中添加一个接口,如下图所示,其中用到了3天以后的时间,以前我们用Calandar来计算日期,但太麻烦,这里介绍一个简单的方法,那就是使用joda-time-2.5.jar这个包,实例化DateTime,然后直接使用plusDays(3)便可以得到3 天后的日期,是不是非常方便。订单生成成功后,我们要跳转到订单生成成功页面,这个页面是success.jsp,这个页面有三个变量需要从Controller传过来,因此我们便在Controller方法中使用Model带回这三个参数。

@RequestMapping("/order/create")这个请求来自于taotao-order-web工程的order-cart.jsp中的隐藏表单,如下图所示。

第五部分:测试
代码写完了,下面我们来测试,我们先将taotao-order工程打包到本地maven仓库,然后用tomcat插件启动taotao-order工程(这个我已经写过太多遍了,就不再写了),然后再重启taotao-order-web工程。

今天看了下工程没法启动的原因,原来是由于发布服务的时候,把ref="orderServiceImpl"写成了ref=“orderService”,导致taotao-order工程启动老是报找不到orderService的错误,细节决定成败,大家写代码的时候一定要细心了。

我们到订单确认页面,点击"提交订单"。

我们会看到如下图所示页面,提示订单提交成功了。

我们再来看看数据库中的数据,可以看到三张表都有数据了。说明我们的订单功能没问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现服务端客户端的连接,可以使用 Java 中的 Socket 类。以下是一个简单的示例代码: ```java // 服务端代码 import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(8888); while (true) { Socket clientSocket = serverSocket.accept(); Thread thread = new Thread(new ServerThread(clientSocket)); thread.start(); } } } // 客户端代码 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class Client { public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost", 8888); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); while (true) { String message = in.readLine(); System.out.println("收到服务端消息:" + message); out.println("客户端收到消息了:" + message); } } } ``` 上面的代码中,服务端监听 8888 端口,当有客户端连接时,就启动一个新的线程处理该客户端的消息。客户端连接时,会向服务端发送消息,服务端收到消息后,会把消息转发给所有连接的客户端。 以下是服务端线程的代码: ```java import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class ServerThread implements Runnable { private Socket clientSocket; public ServerThread(Socket clientSocket) { this.clientSocket = clientSocket; } public void run() { try { BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); while (true) { String message = in.readLine(); System.out.println("收到客户端消息:" + message); out.println("服务端收到消息了:" + message); } } catch (IOException e) { e.printStackTrace(); } } } ``` 在服务端线程中,我们通过输入输出流来和客户端通信,收到消息后,转发给所有客户端

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值