Explorar el Código

Merge branch 'dev' of ssh://10.10.100.21/source/saas-platform into dev

guq hace 7 años
padre
commit
5617c73730
Se han modificado 20 ficheros con 955 adiciones y 20 borrados
  1. 1 0
      applications/pom.xml
  2. 20 0
      applications/transfers/pom.xml
  3. 17 0
      applications/transfers/transfers-api/pom.xml
  4. 64 0
      applications/transfers/transfers-server/pom.xml
  5. 17 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/TransfersApplication.java
  6. 65 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/config/RabbitConfig.java
  7. 106 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/po/MessageInfo.java
  8. 261 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/BaseRabbitReceiveService.java
  9. 52 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/RabbitReceiveService.java
  10. 97 0
      applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/RabbitSendService.java
  11. 63 0
      applications/transfers/transfers-server/src/main/resources/application.yml
  12. 131 0
      applications/transfers/transfers-server/src/main/resources/logback-spring.xml
  13. 36 0
      applications/transfers/transfers-server/src/test/java/com/usoftchina/saas/transfers/service/RabbitSendServiceTest.java
  14. 17 7
      frontend/saas-portal-web/src/components/conenter/addenterprise.vue
  15. 3 0
      frontend/saas-portal-web/src/components/conenter/company.vue
  16. 4 12
      frontend/saas-portal-web/src/components/conenter/invitation.vue
  17. 1 1
      frontend/saas-portal-web/static/css/main.css
  18. BIN
      frontend/saas-portal-web/static/img/caidian2x.png
  19. BIN
      frontend/saas-portal-web/static/img/tijiao.png
  20. BIN
      frontend/saas-portal-web/static/img/tijiao2x.png

+ 1 - 0
applications/pom.xml

@@ -19,6 +19,7 @@
         <module>money</module>
         <module>document</module>
         <module>commons</module>
+        <module>transfers</module>
     </modules>
 
 

+ 20 - 0
applications/transfers/pom.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>applications</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>transfers</artifactId>
+
+    <packaging>pom</packaging>
+    <modules>
+        <module>transfers-api</module>
+        <module>transfers-server</module>
+    </modules>
+
+</project>

+ 17 - 0
applications/transfers/transfers-api/pom.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>transfers</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.usoftchina.saas</groupId>
+    <artifactId>transfers-api</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+
+</project>

+ 64 - 0
applications/transfers/transfers-server/pom.xml

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>transfers</artifactId>
+        <groupId>com.usoftchina.saas</groupId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.usoftchina.saas</groupId>
+    <artifactId>transfers-server</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>server-starter</artifactId>
+        </dependency>
+        <!-- sleuth -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-zipkin</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>net.logstash.logback</groupId>
+            <artifactId>logstash-logback-encoder</artifactId>
+        </dependency>
+        <!-- feign -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+        <!-- test -->
+        <dependency>
+            <groupId>com.usoftchina.saas</groupId>
+            <artifactId>test-starter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>com.spotify</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 17 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/TransfersApplication.java

@@ -0,0 +1,17 @@
+package com.usoftchina.saas.transfers;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+@SpringBootApplication
+@EnableEurekaClient
+@EnableFeignClients("com.usoftchina.saas")
+public class TransfersApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(TransfersApplication.class, args);
+    }
+
+
+}

+ 65 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/config/RabbitConfig.java

@@ -0,0 +1,65 @@
+package com.usoftchina.saas.transfers.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.io.Serializable;
+
+/**
+ * @Description Rabbit配置类
+ * @Author chenwei
+ * @Date 2018/12/28
+ */
+@ConfigurationProperties("spring.rabbitmq")
+public class RabbitConfig implements Serializable {
+
+//    @Value("${spring.rabbitmq.host}")
+    private String host;
+//    @Value("${spring.rabbitmq.port}")
+    private int port;
+//    @Value("${spring.rabbitmq.username}")
+    private String username;
+//    @Value("${spring.rabbitmq.password}")
+    private String password;
+//    @Value("${spring.rabbitmq.virtual-host}")
+    private String virtualHost;
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getVirtualHost() {
+        return virtualHost;
+    }
+
+    public void setVirtualHost(String virtualHost) {
+        this.virtualHost = virtualHost;
+    }
+}

+ 106 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/po/MessageInfo.java

@@ -0,0 +1,106 @@
+package com.usoftchina.saas.transfers.po;
+
+import java.io.Serializable;
+
+/**
+ * @Description 消息内容
+ * @Author chenwei
+ * @Date 2018/12/27
+ */
+public class MessageInfo implements Serializable {
+    /**
+     * 消息ID
+     */
+    private String msgId;
+    /**
+     * 用户ID
+     */
+    private String userId;
+    /**
+     * 应用ID
+     */
+    private String appId;
+    /**
+     * 业务类型
+     */
+    private String bizType;
+    /**
+     * 业务单据ID
+     */
+    private String bizId;
+    /**
+     * 时间戳
+     */
+    private long timestamp;
+    /**
+     * 重试次数
+     */
+    private int retryCount;
+
+    public String getMsgId() {
+        return msgId;
+    }
+
+    public void setMsgId(String msgId) {
+        this.msgId = msgId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getBizType() {
+        return bizType;
+    }
+
+    public void setBizType(String bizType) {
+        this.bizType = bizType;
+    }
+
+    public String getBizId() {
+        return bizId;
+    }
+
+    public void setBizId(String bizId) {
+        this.bizId = bizId;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public int getRetryCount() {
+        return retryCount;
+    }
+
+    public void setRetryCount(int retryCount) {
+        this.retryCount = retryCount;
+    }
+
+    public MessageInfo(String userId, String appId, String bizType, String bizId) {
+        this.userId = userId;
+        this.appId = appId;
+        this.bizType = bizType;
+        this.bizId = bizId;
+    }
+
+    public MessageInfo() {
+
+    }
+}

+ 261 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/BaseRabbitReceiveService.java

@@ -0,0 +1,261 @@
+package com.usoftchina.saas.transfers.service;
+
+import com.rabbitmq.client.AMQP;
+import com.rabbitmq.client.Channel;
+import com.usoftchina.saas.transfers.po.MessageInfo;
+import com.usoftchina.saas.utils.JsonUtils;
+import com.usoftchina.saas.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.AcknowledgeMode;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
+import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
+import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.annotation.AnnotationConfigurationException;
+import org.springframework.messaging.handler.annotation.Headers;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Description RabbitMq 消息接收处理基类
+ * @Author chenwei
+ * @Date 2018/12/27
+ */
+public abstract class BaseRabbitReceiveService implements ChannelAwareMessageListener {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseRabbitReceiveService.class);
+    private static final String DELAY_QUEUE_NAME_SUFFIX = "_delay";
+
+    protected boolean isDynamicCreate = false;
+    protected String host;
+    protected int port;
+    protected String virtualHost;
+    protected String username;
+    protected String password;
+    protected String queueName;
+    //延时时间,单位:毫秒
+    protected String delayTime = "60000";
+    //心跳时间,单位秒
+    protected int requestedHeartBeat = 30;
+    protected String delayQueueName;
+
+    /**
+     * 初始化连接
+     * @return
+     */
+    private ConnectionFactory initConnectionFactory(){
+        if (StringUtils.isEmpty(host)) {
+            throw new IllegalArgumentException("host为空");
+        }
+        if (port <= 0) {
+            throw new IllegalArgumentException("port小于等于0");
+        }
+        if (StringUtils.isEmpty(virtualHost)) {
+            throw new IllegalArgumentException("virtualHost为空");
+        }
+        if (StringUtils.isEmpty(username)) {
+            throw new IllegalArgumentException("username为空");
+        }
+        if (StringUtils.isEmpty(password)) {
+            throw new IllegalArgumentException("password为空");
+        }
+        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
+        connectionFactory.setHost(host);
+        connectionFactory.setPort(port);
+        connectionFactory.setVirtualHost(virtualHost);
+        connectionFactory.setUsername(username);
+        connectionFactory.setPassword(password);
+        connectionFactory.setRequestedHeartBeat(requestedHeartBeat);
+        return connectionFactory;
+    }
+
+    /**
+     * 动态创建消息监听
+     * @return
+     */
+    @Bean
+    protected SimpleMessageListenerContainer simpleMessageListenerContainer(){
+        if (!isDynamicCreate){
+            return null;
+        }
+        if (this.getClass().isAnnotationPresent(RabbitListener.class)){
+            throw new AnnotationConfigurationException("动态创建时,不能配置@RabbitListener注解");
+        }
+        if (StringUtils.isEmpty(queueName)){
+            throw new IllegalArgumentException("queueName为空");
+        }
+        ConnectionFactory connectionFactory = initConnectionFactory();
+        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
+        container.setQueueNames(queueName);
+        //设置手动应答
+        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+        //使用ChannelAwareMessageListener接口,必须实现OnMessage方法
+        container.setMessageListener(this);
+        return container;
+    }
+
+    @Override
+    public void onMessage(Message message, Channel channel) {
+        String messageJson = new String(message.getBody());
+        long tag = message.getMessageProperties().getDeliveryTag();
+        String queueName = message.getMessageProperties().getConsumerQueue();
+        processMessage(messageJson, channel, tag, queueName);
+    }
+
+    /**
+     * 接收消息处理
+     * @param messageBytes
+     * @param channel
+     * @param headers
+     */
+    @RabbitHandler
+    public void receiveMessage(byte[] messageBytes, Channel channel, @Headers Map<String, Object> headers) {
+        receiveMessage(new String(messageBytes), channel, headers);
+    }
+
+    /**
+     * 接收消息处理
+     *
+     * @param messageJson
+     * @param channel
+     * @param headers
+     */
+    @RabbitHandler
+    public void receiveMessage(String messageJson, Channel channel, @Headers Map<String, Object> headers) {
+        long tag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
+        String queueName = (String) headers.get(AmqpHeaders.CONSUMER_QUEUE);
+        processMessage(messageJson, channel, tag, queueName);
+    }
+
+    /**
+     * 处理消息
+     * @param messageJson
+     * @param channel
+     * @param tag
+     * @param queueName
+     */
+    private void processMessage(String messageJson, Channel channel, long tag, String queueName) {
+        MessageInfo messageInfo = getMessageInfo(messageJson);
+        //当消息不符合格式MessageInfo格式时,丢弃消息
+        if (messageInfo == null) {
+            LOGGER.warn("接收消息处理.消息格式.异常,messageJson:{},tag:{}", messageJson, tag);
+            basicNack(channel, tag);
+            return;
+        }
+
+        try {
+            LOGGER.info("接收消息处理[BaseRabbitReceiveService.receiveMessage].处理开始,messageJson:{},tag:{}", messageJson, tag);
+            processMessage(messageInfo);
+            LOGGER.info("接收消息处理[BaseRabbitReceiveService.receiveMessage].处理结束,messageJson:{},tag:{}", messageJson, tag);
+        } catch (Exception e) {
+            LOGGER.error("接收消息处理[BaseRabbitReceiveService.receiveMessage].异常,messageJson:{},tag:{}", messageJson, tag, e);
+            //出现异常时,消息转发为延时消息
+            sendDelayMessage(messageInfo, channel, queueName);
+        } finally {
+            basicAck(channel, tag);
+        }
+    }
+
+    /**
+     * 获取消息内容
+     * @param messageJson
+     * @return
+     */
+    private MessageInfo getMessageInfo(String messageJson) {
+        MessageInfo messageInfo = null;
+        try {
+            messageInfo = JsonUtils.fromJsonString(messageJson, MessageInfo.class);
+        } catch (Exception e) {
+            LOGGER.error("获取消息内容实体[BaseRabbitReceiveService.getMessageInfo].异常,messageJson:{}", messageJson, e);
+
+        }
+        return messageInfo;
+    }
+
+    /**
+     * 发送延时消息
+     * @param messageInfo
+     * @param channel
+     * @param queueName
+     */
+    private void sendDelayMessage(MessageInfo messageInfo, Channel channel, String queueName) {
+        //重试次数+1
+        messageInfo.setRetryCount(messageInfo.getRetryCount() + 1);
+        String messageJson = JsonUtils.toJsonString(messageInfo);
+        try {
+            String dQueueName = getDelayQueueName(channel, queueName);
+            AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
+            //设置延时时间
+            builder.expiration(delayTime);
+            channel.basicPublish("", dQueueName, builder.build(), messageJson.getBytes());
+            LOGGER.info("发送延时消息[BaseRabbitReceiveService.sendDelayMessage].正常,messageJson:{},queueName:{}", messageJson, queueName);
+        } catch (IOException e) {
+            LOGGER.error("发送延时消息[BaseRabbitReceiveService.sendDelayMessage].异常,messageJson:{},queueName:{}", messageJson, queueName, e);
+        }
+    }
+
+    /**
+     * 获取延时队列
+     * @param channel
+     * @param queueName
+     * @return
+     * @throws IOException
+     */
+    private String getDelayQueueName(Channel channel, String queueName) throws IOException {
+        if (!StringUtils.isEmpty(delayQueueName)) {
+            return delayQueueName;
+        }
+        //初始化延时队列
+        String dQueueName = queueName + DELAY_QUEUE_NAME_SUFFIX;
+        Map<String, Object> arguments = new HashMap<String, Object>(2);
+        arguments.put("x-dead-letter-exchange", "");
+        arguments.put("x-dead-letter-routing-key", queueName);
+        channel.queueDeclare(dQueueName, true, false, false, arguments);
+        delayQueueName = dQueueName;
+        return dQueueName;
+    }
+
+    /**
+     * 消息应答No
+     * @param channel
+     * @param tag
+     */
+    private void basicNack(Channel channel, long tag) {
+        try {
+            channel.basicNack(tag, false, false);
+            LOGGER.info("接收消息处理.消息应答No[BaseRabbitReceiveService.receiveMessage.basicNack].正常,tag:{}", tag);
+        } catch (IOException e) {
+            LOGGER.error("接收消息处理.消息应答No[BaseRabbitReceiveService.receiveMessage.basicNack].异常,tag:{}", tag, e);
+        }
+    }
+
+    /**
+     * 消息应答Yes
+     * @param channel
+     * @param tag
+     */
+    private void basicAck(Channel channel, long tag) {
+        try {
+            channel.basicAck(tag, false);
+            LOGGER.info("接收消息处理.消息应答Yes[BaseRabbitReceiveService.receiveMessage.basicAck].正常,tag:{}", tag);
+        } catch (IOException e) {
+            LOGGER.error("接收消息处理.消息应答Yes[BaseRabbitReceiveService.receiveMessage.basicAck].异常,tag:{}", tag, e);
+        }
+    }
+
+    /**
+     * 处理消息
+     * @param messageInfo
+     * @throws Exception
+     */
+    public abstract void processMessage(MessageInfo messageInfo) throws Exception;
+
+}

+ 52 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/RabbitReceiveService.java

@@ -0,0 +1,52 @@
+package com.usoftchina.saas.transfers.service;
+
+import com.usoftchina.saas.transfers.config.RabbitConfig;
+import com.usoftchina.saas.transfers.po.MessageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @Description 消息消费
+ * @Author chenwei
+ * @Date 2018/12/28
+ */
+@Service
+@EnableConfigurationProperties(RabbitConfig.class)
+public class RabbitReceiveService extends BaseRabbitReceiveService {
+
+    @Autowired
+    private RabbitConfig rabbitConfig;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitReceiveService.class);
+    private static final String QUEUENAME = "saas_trade";
+
+    @PostConstruct
+    public void init(){
+        isDynamicCreate = true;
+        host = rabbitConfig.getHost();
+        port = rabbitConfig.getPort();
+        username = rabbitConfig.getUsername();
+        password = rabbitConfig.getPassword();
+        virtualHost = rabbitConfig.getVirtualHost();
+        queueName = QUEUENAME;
+    }
+
+    @Override
+    public void processMessage(MessageInfo messageInfo) throws Exception {
+        switch (messageInfo.getAppId()){
+            case "trade":
+                processMessageForReceivable(messageInfo.getBizId(), messageInfo.getBizType());
+            default:
+                break;
+        }
+    }
+
+    private void processMessageForReceivable(String bizId, String bizType) {
+        LOGGER.info("消费消息,bizId:{}, bizType:{}", bizId, bizType);
+    }
+}

+ 97 - 0
applications/transfers/transfers-server/src/main/java/com/usoftchina/saas/transfers/service/RabbitSendService.java

@@ -0,0 +1,97 @@
+package com.usoftchina.saas.transfers.service;
+
+import com.usoftchina.saas.transfers.po.MessageInfo;
+import com.usoftchina.saas.utils.JsonUtils;
+import com.usoftchina.saas.utils.ObjectUtils;
+import com.usoftchina.saas.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.support.CorrelationData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.UUID;
+
+/**
+ * @Description RabbitMQ发送消息
+ * @Author chenwei
+ * @Date 2018/12/27
+ */
+@Service
+public class RabbitSendService implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitSendService.class);
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @PostConstruct
+    public void init(){
+        //如果消息没有到exchange,则confirm回调,ack=false
+        //如果消息到达exchange,则confirm回调,ack=true
+        //exchange到queue成功,则不回调return
+        //exchange到queue失败,则回调return(否则不回回调,消息就丢了)
+        rabbitTemplate.setConfirmCallback(this);
+        rabbitTemplate.setReturnCallback(this);
+    }
+
+    /**
+     *
+     * @param queueName 队列名
+     * @param userId    用户ID
+     * @param appId     应用
+     * @param bizType   业务类型
+     * @param bizId     业务ID
+     * @return  消息ID
+     */
+    public String sendMessage(String queueName, String userId, String appId, String bizType, String bizId){
+        MessageInfo messageInfo = new MessageInfo(userId, appId, bizType, bizId);
+        return sendMessage(queueName, messageInfo);
+    }
+
+    /**
+     * 发送消息
+     * @param queueName     队列名
+     * @param messageInfo   消息体
+     * @return
+     */
+    public String sendMessage(String queueName, MessageInfo messageInfo){
+        if (StringUtils.isEmpty(queueName)){
+            throw new IllegalArgumentException("QueueName(队列名)不能为空!");
+        }
+        if (ObjectUtils.isEmpty(messageInfo)){
+            throw new IllegalArgumentException("messageInfo(消息体)不能为空!");
+        }
+        //消息ID
+        messageInfo.setMsgId(UUID.randomUUID().toString());
+        //时间戳
+        messageInfo.setTimestamp(System.currentTimeMillis());
+        CorrelationData correlationData = new CorrelationData(messageInfo.getMsgId());
+        String messageJson = JsonUtils.toJsonString(messageInfo);
+        rabbitTemplate.convertAndSend(queueName, (Object) messageJson, correlationData);
+        LOGGER.info("发送消息[RabbitSendService.sendMessage].正常,queueName:{},messageInfo:{},correlationData:{}",
+                queueName, messageJson, correlationData.getId());
+        return messageInfo.getMsgId();
+    }
+
+    @Override
+    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+        if (ack){
+            LOGGER.info("发送消息确认[RabbitSendService.confirm].正常,correlationData:{}",
+                    correlationData.getId());
+        }else {
+            LOGGER.info("发送消息确认[RabbitSendService.confirm].正常,correlationData:{}",
+                    correlationData.getId(), cause);
+        }
+    }
+
+    @Override
+    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
+        LOGGER.error("发送消息确认到达队列[RabbitSendService.returnedMessage].异常," +
+                "message:{},replyCode:{},replyText:{},exchange:{},routingKey:{}",
+                message, replyCode, replyText, exchange, routingKey);
+    }
+}

+ 63 - 0
applications/transfers/transfers-server/src/main/resources/application.yml

@@ -0,0 +1,63 @@
+spring:
+  application:
+    name: transfers-server
+  security:
+    user:
+      name: admin
+      password: select111***
+  messages:
+    basename: i18n/messages
+    encoding: UTF-8
+  rabbitmq:
+    host: 10.1.81.75
+    port: 5672
+    virtual-host: dev
+    username: saas
+    password: select123***
+  zipkin:
+    sender:
+      type: rabbit
+    locator:
+      discovery:
+        enabled: true
+  sleuth:
+    sampler:
+      probability: 1.0
+  redis:
+    host: 10.1.81.62
+    port: 6379
+management:
+  endpoints:
+    web:
+      exposure:
+        include: "*"
+  endpoint:
+    health:
+      show-details: always
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    health-check-url-path: /actuator/health
+    status-page-url-path: /actuator/info
+    metadata-map:
+      user.name: ${spring.security.user.name}
+      user.password: ${spring.security.user.password}
+  client:
+    registryFetchIntervalSeconds: 5
+    serviceUrl:
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@10.1.81.61:8510/eureka/
+server:
+  port: 8960
+  tomcat:
+    uri-encoding: UTF-8
+info:
+  name: '@project.artifactId@'
+  description: '@project.description@'
+  version: '@project.version@'
+  spring-boot-version: '@spring.boot.version@'
+  spring-cloud-version: '@spring.cloud.version@'
+auth:
+  public-key: auth/pub.key
+ribbon:
+  ReadTimeout: 10000
+  ConnectTimeout: 10000

+ 131 - 0
applications/transfers/transfers-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <include resource="org/springframework/boot/logging/logback/base.xml" />
+    <jmxConfigurator/>
+
+    <!--
+    %m
+    输出代码中指定的消息
+    %p
+    输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
+    %r
+    输出自应用启动到输出该log信息耗费的毫秒数
+    %c
+    输出所属的类目,通常就是所在类的全名
+    %t
+    输出产生该日志事件的线程名
+    %n
+    输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
+    %d
+    输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},
+    输出类似:2002年10月18日 22:10:28,921
+    %l
+    输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
+    -->
+
+    <springProperty scope="context" name="log.path" source="logging.path" defaultValue="/var/log/saas/transfers-server"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name" defaultValue="transfers-server"/>
+    <springProperty scope="context" name="spring.profiles.active" source="spring.profiles.active" defaultValue="dev"/>
+    <springProperty scope="context" name="common-pattern" source="logging.common-pattern" defaultValue="%d{yyyy-MM-dd HH:mm:ss.SSS}:[%5p] [%t:%r] [%C{1}:%M:%L] --> %m%n"/>
+    <springProperty scope="context" name="log.level.console" source="logging.level.console" defaultValue="INFO"/>
+    <springProperty scope="context" name="log.destination" source="logging.destination" defaultValue="192.168.0.63:5000"/>
+
+    <contextName>${spring.application.name}-${spring.profiles.active}-logback</contextName>
+
+    <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender">
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${log.level.console}</level>
+        </filter>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="ROOT_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/root.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${log.path}/%d{yyyy-MM}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
+            <maxFileSize>128MB</maxFileSize>
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${common-pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- Appender to log in a JSON format -->
+    <appender name="JSON_APPENDER" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
+        <destination>${log.destination}</destination>
+        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
+            <providers>
+                <pattern>
+                    <pattern>
+                        {
+                        "severity": "%level",
+                        "service": "${spring.application.name:-}",
+                        "trace": "%X{X-B3-TraceId:-}",
+                        "span": "%X{X-B3-SpanId:-}",
+                        "parent": "%X{X-B3-ParentSpanId:-}",
+                        "exportable": "%X{X-Span-Export:-}",
+                        "pid": "${PID:-}",
+                        "thread": "%thread",
+                        "class": "%logger{40}",
+                        "rest": "%message"
+                        }
+                    </pattern>
+                </pattern>
+            </providers>
+        </encoder>
+    </appender>
+
+    <logger name="org.springframework" level="INFO"/>
+    <logger name="com.usoftchina.saas" level="INFO"/>
+
+    <springProfile name="dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="test">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="ROOT_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.saas" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-dev">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-test">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.saas" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+    <springProfile name="docker-prod">
+        <logger name="org.springframework" level="WARN"/>
+        <logger name="com.usoftchina.saas" level="WARN"/>
+        <root level="WARN">
+            <appender-ref ref="CONSOLE_APPENDER"/>
+            <appender-ref ref="JSON_APPENDER"/>
+        </root>
+    </springProfile>
+
+</configuration>

+ 36 - 0
applications/transfers/transfers-server/src/test/java/com/usoftchina/saas/transfers/service/RabbitSendServiceTest.java

@@ -0,0 +1,36 @@
+package com.usoftchina.saas.transfers.service;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @Description 消息生成测试
+ * @Author chenwei
+ * @Date 2018/12/28
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+@EnableAutoConfiguration
+public class RabbitSendServiceTest {
+
+    @Autowired
+    private RabbitSendService rabbitSendService;
+
+    private final String QUEUENAME = "saas_trade";
+    private final String USERID = "1";
+    private final String APPID = "trade";
+    private final String BIZTYPE = "PURCHASE";
+    private final String BIZID = "1";
+
+
+    @Test
+    public void sendMessage() throws Exception {
+        String messageId = rabbitSendService.sendMessage(QUEUENAME, USERID, APPID, BIZTYPE, BIZID);
+        System.out.println(messageId);
+    }
+
+}

+ 17 - 7
frontend/saas-portal-web/src/components/conenter/addenterprise.vue

@@ -154,6 +154,7 @@ import { setTimeout, clearTimeout } from 'timers';
                 isqyaddress:false,//地址
                 isyzusername:false,
                 isheidemail:false,
+                iscompanyname:false,
             }
         },
         components:{
@@ -324,12 +325,21 @@ import { setTimeout, clearTimeout } from 'timers';
             },
             // 选择要加入的企业
             qylist(i){
-                this.companyId = this.arr[i].id,
-                this.admin = this.arr[i].admin,
-                this.newindex = i,
-                this.$refs.lookupqyname.value = this.arr[i].name,
+                let companyName = JSON.parse(window.sessionStorage.getItem("companyname"));
+                this.companyId = this.arr[i].id;
+                this.admin = this.arr[i].admin;
+                this.newindex = i;
+                this.$refs.lookupqyname.value = this.arr[i].name;
                 this.islookup = false;
-                if (this.admin == this.mytoken.account.realname) {
+                for (let j = 0; j < companyName.length; j++) {
+                    if (this.arr[i].name == companyName[j]) {
+                        this.iscompanyname = true
+                        break
+                    } else {
+                        this.iscompanyname = false
+                    }
+                }
+                if (this.iscompanyname || this.admin == this.mytoken.account.realname) {
                     this.$refs.warningqyname.innerHTML = '<img style="width:14px" src="/static/img/warning.png" alt=""> 账号已在企业服务中,不能重复加入';
                 } else {
                     this.$refs.warningqyname.innerHTML = '<img style="width:14px" src="/static/img/ok.png" alt="">';
@@ -342,7 +352,6 @@ import { setTimeout, clearTimeout } from 'timers';
             },
             //加入企业提交按钮
             Submission(){
-                this.$store.state.isloading = true;
                 let token = this.mytoken.token;
                 let qyname = this.$refs.lookupqyname.value.replace(/\s+/g, "");//企业名字
                 let username = this.$refs.lookupname.value.replace(/\s+/g, "");//姓名过滤空格
@@ -352,13 +361,14 @@ import { setTimeout, clearTimeout } from 'timers';
                     this.$message.error('企业或管理员不存在');
                 } else if (!this.companyId) {
                     this.$message.error('请选择要加入的企业');
-                } else if (this.admin == this.mytoken.account.realname) {
+                } else if (this.admin == this.mytoken.account.realname || this.iscompanyname) {
                     this.$message.error('账号已在企业服务中,不能重复加入');
                 } else if (!this.isTestingname) {
                     this.$message.error('姓名不能为空');
                 } else if (!this.isregname) {
                     this.$message.error('姓名不能包含符号、数字等非法字符');
                 } else {
+                    this.$store.state.isloading = true;
                     this.$ajax({
                         url: this.$url.api+'/api/account/accountCenter/company/join',
                         method:'POST',

+ 3 - 0
frontend/saas-portal-web/src/components/conenter/company.vue

@@ -173,7 +173,10 @@
                         this.list = res.data.data.spaces;
                         this.pagingtion(1,this.size);
                         let enterprise = [];
+                        let qyname = [];
                         for (let i = 0; i < this.list.length; i++) {
+                            qyname.push(this.list[i].name);
+                            window.sessionStorage.setItem('companyname',JSON.stringify(qyname))
                             if (this.list[i].saas_) {
                                 let addenterprise = {'id':'', 'logoUrl': '', 'name': '','dcName':''};
                                 addenterprise.id = this.list[i].id;

+ 4 - 12
frontend/saas-portal-web/src/components/conenter/invitation.vue

@@ -4,8 +4,8 @@
         <div class="Popup" v-if="istanchaung">
         <!-- <div class="Popup"> -->
             <div class="shang">
-                <img src="/static/img/caidian2x.png" alt="">
-                <img src="/static/img/tijiao2x.png" alt="">
+                <!-- <img src="/static/img/caidian2x.png" alt=""> -->
+                <img src="/static/img/tijiao.png" alt="">
                 <img class="xs" @click="hidden" src="/static/img/assets/chahao.png" alt="">
             </div>
             <div class="zhong">
@@ -431,20 +431,12 @@ import { setTimeout } from 'timers';
     height: 30%;
     position: relative;
 }
-.shang > img {
-    position: absolute;
-}
 .shang > img:nth-child(1){
-    top: 15px;
-    left: 34%;
     width: 124px;
+    margin-top: 15px;
 }
 .shang > img:nth-child(2){
-    top: 18px;
-    left: 38%;
-    width: 101px;
-}
-.shang > img:nth-child(3){
+    position: absolute;
     top: 0px;
     right: 0px;
 }

+ 1 - 1
frontend/saas-portal-web/static/css/main.css

@@ -101,7 +101,7 @@ main > section {
     height: 100%;
     width: 100%;
     background: #000;
-    opacity: 0.3;
+    opacity: 0.35;
     z-index: 10000;
 }
 /* 登录弹窗 */

BIN
frontend/saas-portal-web/static/img/caidian2x.png


BIN
frontend/saas-portal-web/static/img/tijiao.png


BIN
frontend/saas-portal-web/static/img/tijiao2x.png