activeMQ实践(三)---用spring-activemq实现图书的新增

前两篇我们了解了activeMQ的概念和一般使用方法,但凡Java出彩的中间件和开源项目都绕不开spring这座大山,我们就来看看结合spring的实际应用,在这之前我想大家平常都会使用京东购物,每次付款成功后,系统app会先提示我们下单成功,很快再次提示订单已生成,这其中就是消息中间件的作用,当并发数高的时候直接对数据库操作,会对数据库造成过大的压力,所以先把下单信息放到中间件提示用户下单成功,插入数据库后再告诉客户订单生成,当然京东的架构不像我说的这么简单,我描述个大概。
那么让我们简单基于activeMQ实现一下添加书籍的功能,我之前写过一个简单的ssm项目,这里直接拿来用,链接在这十二步用ssm+bootstrsp搭建简单易上手的小型图书系统
新的项目结构图:
这里写图片描述
那么首先添加好pom文件的依赖:

        <!-- xbean 如<amq:connectionFactory /> -->
        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <!-- activemq -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>5.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
            <version>5.12.1</version>
        </dependency>

第二步:构建activemq.xml文件,将spring和activemq结合起来

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:amq="http://activemq.apache.org/schema/core"
       xmlns:jms="http://www.springframework.org/schema/jms"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.12.1.xsd"
>

    <context:component-scan base-package="cn.com.activimq" />
    <mvc:annotation-driven />
    <!-- 这里配置activemq连接工厂,连接activemq -->
    <bean id="activeMQConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://localhost:61616"/>
    </bean>

    <!-- 配置JMS连接工长,结合spring自然是通过spring-jms的连接工厂来实现的 -->
    <bean id="connectionFactory"
          class="org.springframework.jms.connection.SingleConnectionFactory">
        <constructor-arg ref="activeMQConnectionFactory" />

    </bean>

    <!-- 一个队列目的地,点对点;队列和主题模式之前已经讲过了 -->
    <bean id ="queueDestination" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg  value="spring-queue" />
    </bean>
    <!-- 主题目的地 -->
    <bean id ="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg  value="spring-topic" />
    </bean>
    <!-- JmsTemplate Definition -->
    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="defaultDestination" ref="queueDestination" />
    </bean>

    <!-- 配置监听器,监听器的作用就是一有消息消费者可以自动接收处理 -->
    <bean id="consumerMessageListener" class="cn.com.activimq.consumer.ConsumerMessageListener"></bean>
    <!-- 配置消息容器,目的地destination随模式更换即可 -->
    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory"></property>
        <property name="destination" ref="topicDestination"></property>
        <property name="messageListener" ref="consumerMessageListener"></property>
    </bean>

    <bean id="producerServiceImpl" class="cn.com.activimq.producer.ProducerServiceImpl"></bean>
</beans>

当然我们不能忘记要在web.xml中将activemq.xml加载进去

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">
    <!-- 配置DispatcherServlet -->
    <servlet>
        <servlet-name>seckill-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置springMVC需要加载的配置文件
            spring-dao.xml,spring-service.xml,spring-web.xml
            Mybatis - > spring -> springmvc
         -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:Spring/spring-*.xml
                classpath:Spring/activemq.xml
            </param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>seckill-dispatcher</servlet-name>
        <!-- 默认匹配所有的请求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

第三步:将我们之前写的生产者拉进来,一个ProducerService接口,一个ProducerServiceImpl实现

package cn.com.activimq.producer;

public interface ProducerService {
    void sendMessage(String message);
}
package cn.com.activimq.producer;

import javax.annotation.Resource;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;


public class ProducerServiceImpl implements ProducerService{
    @Autowired
    JmsTemplate jmsTemplate;
    @Resource(name ="topicDestination")
    Destination destination;
    @Override
    public void sendMessage(final String message) {
        //使用jmsTemplate发送消息
        jmsTemplate.send(destination,new MessageCreator(){
            @Override
            public Message createMessage(Session session) throws JMSException {
                TextMessage textMessage = session.createTextMessage(message);
                System.out.println("发送消息"+textMessage.getText());
                return textMessage;
            }

        });
        System.out.println("发送消息"+message);
    }

}

第四步:在BookController中将添加图书的消息先存到activemq中去

package cn.com.controller;

import cn.com.activimq.producer.ProducerServiceImpl;
import cn.com.entity.Book;
import cn.com.service.BookService;
import java.util.List;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/**
 * ${DESCRIPTION}
 *
 * @author lightTrace
 * @create 2017-10-26 21:57
 **/
@Controller
@RequestMapping("/book")
public class BookController {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private BookService bookService;
    @Resource
    private ProducerServiceImpl producerServiceImpl;
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    private String list(Model model) {
        List<Book> list = bookService.getList(0, 1000);
        model.addAttribute("list", list);
        return "list";// WEB-INF/jsp/"list".jsp
    }
    @RequestMapping(value = "/addPage", method = RequestMethod.GET)
    private String addPage(Model model) {
        return "add";// WEB-INF/jsp/"list".jsp
    }
    @RequestMapping(value = "/detail/{bookId}", method = RequestMethod.GET)
    private String detail(@PathVariable("bookId") Long bookId, Model model) {
        Book book = bookService.getById(bookId);
        model.addAttribute("book", book);
        return "detail";
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST, produces = "text/plain;charset=UTF-8")
    private String add(Book book,Model model) {
          Book hasBook = bookService.getById(book.getBookId());
          String bookJsonString = JSON.toJSONString(book);
          //将添加的book对象信息转换为json字符串传输到activemq中去
          producerServiceImpl.sendMessage(bookJsonString);
          return "list";
    }

    @RequestMapping(value = "/del/{bookId}", method = RequestMethod.GET)
    @ResponseBody
    private String deleteBookById(@PathVariable("bookId") Long id) {
        int i = bookService.deleteBookById(id);
        return i > 0 ? "success" : "error";
    }
}

第五步:通过监听器将添加图书的信息通过BookService消费掉:

package cn.com.activimq.consumer;

import cn.com.entity.Book;
import cn.com.service.BookService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

public class ConsumerMessageListener implements MessageListener{
    @Autowired
    private BookService bookService;
    @Override
    public void onMessage(Message message) {
       TextMessage textMessage = (TextMessage) message;
        try {
            Book book = JSON.parseObject(textMessage.getText(), Book.class);
            bookService.addBook(book);
            System.out.println("接收消息"+textMessage.getText());
    } catch (JMSException e) {
        e.printStackTrace();
    }
    }

}

第六步:自然是添加一个添加图书的jsp页面,在添加图书信息那里

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% String appPath = request.getContextPath(); %>
<html>
<head>
    <title>添加图书</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 Shim 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
    <!-- 注意: 如果通过 file://  引入 Respond.js 文件,则该文件无法起效果 -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
    <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
    <![endif]-->
</head>
<body>
<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="page-header">
                <h1>
                    <small>图书管理系统 - 添加图书</small>
                </h1>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-12 column">
            <ul class="nav nav-tabs">
                <li><a href="<%=appPath%>/book/list">首页</a></li>
                <li class="active"><a href="<%=appPath%>/book/detail/1003">图书具体信息</a></li>
                <li class="disabled"><a href="#">信息</a></li>
            </ul>
        </div>
    </div>

    <form action="${pageContext.request.contextPath}/book/add" method="POST">

            <P style="padding: 30px 0px 10px; position: relative;">
                <SPAN class="u_logo"></SPAN>
                <INPUT id="bookId" name="bookId" class="ipt" type="text"
                       placeholder="请输入书号" value="${book.bookId}">
            </P>
            <P style="position: relative;">
                <SPAN class="p_logo"></SPAN>
                <INPUT id="name" name="name" class="ipt" type="text"
                       placeholder="请输入书名" value="${book.name }">
            </P>
            <P style="position: relative;">
                <SPAN class="p_logo"></SPAN>
                <INPUT id="number" name="number" class="ipt" type="text"
                       placeholder="请输入书页数" value="${book.number }">
            </P>
            <P style="position: relative;">
                <SPAN class="p_logo"></SPAN>
                <INPUT id="detail" name="detail" class="ipt" type="text"
                       placeholder="请输入书描述" value="${book.detail }">
            </P>
            <DIV
                    style="height: 50px; line-height: 50px; margin-top: 30px; border-top-color: rgb(231, 231, 231); border-top-width: 1px; border-top-style: solid;">
                <P style="margin: 0px 35px 20px 45px;">
                    <SPAN style="float: left;">图书管理系统</SPAN>
                    <span><font color="red" id="error">${errorInfo }</font></span>
                    <SPAN
                            style="float: right;">
                        <input type="submit"
                               style="background: rgb(0, 142, 173); padding: 7px 10px; border-radius: 4px; border: 1px solid rgb(26, 117, 152); border-image: none; color: rgb(255, 255, 255); font-weight: bold;"
                               value="添加" />
                    </SPAN>
                </P>
            </DIV>
        </DIV>
    </form>
</div>

<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<script src="https://code.jquery.com/jquery.js"></script>
</body>
</html>

末了记得修改list.jsp页面的跳转:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<% String appPath = request.getContextPath(); %>
<html>
<head>
    <title>图书列表</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="page-header">
                <h1>
                     <small>图书管理系统 </small>
                </h1>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-12 column">
            <ul class="nav nav-tabs">
                <li class="active"><a href="<%=appPath%>/book/list">首页</a></li>
                <li><a href="<%=appPath%>/book/detail/1000">图书具体信息</a></li>
                <li><a href="<%=appPath%>/book/addPage">添加图书信息</a></li>
                <li class="disabled"><a href="#">信息</a></li>
            </ul>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-12 column">
            <div class="page-header">
                <h1>图书列表 <small>显示当前图书库存信息</small></h1>
            </div>
        </div>
    </div>
    <div class="row clearfix">
        <div class="col-md-12 column">
            <table class="table table-hover table-striped">
                <thead>
                <tr>
                    <th>图书编号</th>
                    <th>图书名字</th>
                    <th>图书数量</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                <c:forEach var="book" items="${requestScope.get('list')}" varStatus="status">
                    <tr>
                        <td>${book.bookId}</td>
                        <td>${book.name}</td>
                        <td>${book.number}</td>
                        <td>
                            <a href="<%=appPath%>/book/detail/${book.bookId}">详情</a> |
                            <a href="<%=appPath%>/book/del/${book.bookId}">删除</a>
                        </td>

                    </tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
    </div>
</div>

<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<script src="https://code.jquery.com/jquery.js"></script>
</body>
</html

效果图:
上传图书
activemq消息,接收后立马被bookservice消费
上传结果
通过代码的构建我们发现activemq就是将controller和service层测底的解耦了,controller只需要把消息异步传递出去,却不管你service怎么处理.
项目github地址:小型图书管理系统扩展activemq

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值