如何通过MQ在openAPI开发异步接口原创
金蝶云社区-范老师加油
范老师加油
3人赞赏了该文章 1,120次浏览 未经作者许可,禁止转载编辑于2022年12月28日 10:09:16

关键词:接口开发,异步接口,MQ

一、需求

openAPI目前是不支持通过配置做成异步接口开发的,这就需要我们通过开发平台的自定义接口来自己实现的。

二、思路与方案

关于如何开发 自定义的接口可以参考下这个文章:

https://vip.kingdee.com/knowledge/specialDetail/226337046514476288?category=358247193897143040&id=294499338368404736&productLineId=29


MQ的案例也可以参阅这个文章:

https://vip.kingdee.com/article/316882666815440896?productLineId=29&isKnowledge=2

我们这次以通过接口生成学生信息为例,给大家演示下如何创建。


三、实现过程

1    创建单据元数据

新建一个学生信息单,在单据头加上名称和年级。

在分录上加上,学科编码,学科名称,成绩

image.png


2   编写接口controller

@ApiController(value="Student",desc="保存学生信息")
public class SaveStudentApiController {
	@ApiPostMapping(value="saveStudent")
	public CustomApiResult<String> saveStudentApi(@Valid @ApiParam("学生信息") SaveStudentReqModel data) {
		MessagePublisher mp = MQFactory.get().createSimplePublisher("bidt", "savestudent_queue");
		try{
		     mp.publish(data);
		     return CustomApiResult.success("调用接收成功!");
		}catch(Exception e) {
			 return CustomApiResult.fail("500", "异步处理失败!");
		}finally{
		     mp.close();
		}
	}
}


3 编写api请求model


import java.io.Serializable;
import java.util.List;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import kd.bos.openapi.common.custom.annotation.ApiModel;
import kd.bos.openapi.common.custom.annotation.ApiParam;

@ApiModel
public class SaveStudentReqModel implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@ApiParam("number")
	private String number;
	@ApiParam("name")
	private String name;
	@ApiParam("grade")
	private String grade;
	
	@ApiParam("分录")
	public List<Subject > subList;
	@ApiModel
	public static class Subject  implements Serializable {
		@ApiParam("学科编码")
		private String subjectNum;
		@ApiParam("学科名称")
		@NotNull 
		private String subjectName;
		@Max(100)
		@Min(0)
		@ApiParam("成绩")		 
		private int score;
		public String getSubjectNum() {
			return subjectNum;
		}
		public void setSubjectNum(String subjectNum) {
			this.subjectNum = subjectNum;
		}
		public String getSubjectName() {
			return subjectName;
		}
		public void setSubjectName(String subjectName) {
			this.subjectName = subjectName;
		}
		public int getScore() {
			return score;
		}
		public void setScore(int score) {
			this.score = score;
		}
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGrade() {
		return grade;
	}
	public void setGrade(String grade) {
		this.grade = grade;
	}
	public List<Subject> getSubList() {
		return subList;
	}
	public void setSubList(List<Subject> subList) {
		this.subList = subList;
	}
	
	
}

4  在开放平台配置接口

  第一步在api管理新增接口

image.png

image.png

第二步

在类名处把刚才写好全类名controller 粘贴过去,系统就会自动加载类里面的属性和方法了,不再需要我们手动填入了。

完善名称就可以保存了(在这里你也可以稍微改动下一些备注说明)


image.png


5 编写消费类

import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.mq.MessageAcker;
import kd.bos.mq.MessageConsumer;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import test.api.SaveStudentReqModel.Subject;
public class SaveStudentConsumer implements MessageConsumer {
   Log log = LogFactory.getLog(getClass());
   @Override
   public void onMessage(Object message, String messageId, boolean resend, MessageAcker acker) {
      log.info("自定义DemoConsumer开始消费");
      try {
    	  SaveStudentReqModel student = (SaveStudentReqModel)message;
    	  //组装数据
    	  DynamicObject newStudent =BusinessDataServiceHelper.newDynamicObject("bidt_student_object");
		  newStudent.set("billno",student.getNumber());
		  newStudent.set("bidt_name", student.getName());
		  newStudent.set("billstatus", "B");
		  newStudent.set("bidt_grade",student.getGrade());
		  for (Subject sub:student.getSubList()) {
			  DynamicObjectCollection subEntryCols = newStudent.getDynamicObjectCollection("entryentity");
			  DynamicObject subEntryCol =  new DynamicObject(subEntryCols.getDynamicObjectType());
			  subEntryCol.set("bidt_subject_num", sub.getSubjectNum());
			  subEntryCol.set("bidt_subject_name", sub.getSubjectName());
			  subEntryCol.set("bidt_score", sub.getScore());
			  subEntryCols.add(subEntryCol);
		  }
		  SaveServiceHelper.saveOperate("bidt_student_object",new DynamicObject[] {newStudent});
      } catch (Throwable e) {
         boolean discard = false; //是否废弃这条消息,根据具体场景判断
         if (discard){
            acker.discard(messageId);//废弃
            // 记录废弃原因,并写业务日志
         } else{
            acker.deny(messageId);//告诉mq重发这条消息
            // 记录异常原因,并写业务日志
         }
      }
   }
}

6  编写mqconfig文件

在main目录下的resources文件里面创建一个xml文件

image.png

文件里面代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<root> 
	<region name="bidt">
		<queue name="savestudent_queue" appid="bidt_yanzheng">
            <consumer class="test.api.SaveStudentConsumer"></consumer>
        </queue>
	</region>
</root>


文件里面写的region 对应controller类代码里的第一个参数,queue对应controller类代码里的第二个参数。

MessagePublisher mp = MQFactory.get().createSimplePublisher("bidt", "savestudent_queue");


7 在添加启动参数

  这里有两种方式添加,一种是启动类DebugServer.java里面添加,这种比较简单,一般是轻量级里面都是这样加的


System.setProperty("dubbo.registry.register", "true");
System.setProperty("mq.consumer.register", "true");
//定义一个唯一的标识别和其他人重复
System.setProperty("mq.debug.queue.tag", "sharkv");
System.setProperty("lightweightdeploy","false");
//队列发送方、消费方均需要该配置项,包括具体的配置文件,生产环境可配在服务节点的启动参数中
System.setProperty("mqConfigFiles.config","testmqconfig.xml");

还有一种是在mc里面添加,协同及生产环境都可以在这里添加

MC:公共配置方案,/root/config/mservice/prop中新增mqConfigFiles.config参数

注:如果有多个xml文件,换行即可

image.png



这里也要提一点,经常有人会出现 rabbitmq config error: queue not configured for xxx/xxx的问题

这里就要查看下是否是路径问题,打包的时候是否把xml编译到其他文件目录下的,否则也会在启动的时候扫描不到xml文件,导致找不到queue的问题


image.png

其他的排查思路可以参考下

https://vip.kingdee.com/article/230271851040272896?productLineId=29


8 重新启动服务

启动后通过mq的管理服务器就可以看到我们刚才配置队列已经启动好了

image.png


四、效果图

1 通过开发平台自带测试开始测试

image.png

2 这里已经看到进入了消费类进行消费了。


image.png


3  跳过调试,跑完后,进入单据查看,发现已经正确生成了。

image.png



五、开发环境版本

COSMICV5.0.003.0

六、参考资料

【开发平台】指导手册

学习成长中心


赞 3