Filter
import com.google.common.base.Charsets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.onlyedu.maindata.Constant.LISTENER_URL_PREFIX;
/**
* @author qbit
*/
@Slf4j
@Component
public class SinkToRabbitmq implements Filter {
//我们约定所有接收消息的api的url格式为/${LISTENER_URL_PREFIX}/${exchange}/${topic}
private static final String LISTENER_URL_PREFIX="/listener/";
//对于get请求同步转发给后端swagger服务,这样可以对外显示文档(但是无法调用)
private static final String SWAGGER_ADDRESS="http://swagger:8080";
private final RestTemplate restTemplate=new RestTemplate();
private final AmqpTemplate amqpTemplate;
//对于所有请求均返回成功
private static final String SUCCESS = "SUCCESS ";
public SinkToRabbitmq(AmqpTemplate amqpTemplate) {
this.amqpTemplate = amqpTemplate;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response=(HttpServletResponse)servletResponse;
String uri = request.getRequestURI();
if (!uri.startsWith(LISTENER_URL_PREFIX)) {
var repositoryResponse=restTemplate.getForEntity(SWAGGER_ADDRESS+uri,String.class);
response.setStatus(repositoryResponse.getStatusCodeValue());
try (ServletOutputStream os = servletResponse.getOutputStream()) {
os.write(repositoryResponse.getBody().getBytes(Charsets.UTF_8));
}
} else {
String body = StreamUtils.copyToString(request.getInputStream(), Charsets.UTF_8);
//记录下日志用于自己重放请求
log.info("curl -X " + request.getMethod() + " --header 'Content-Type: application/json' --header 'Accept: */*' -d '" + body.replaceAll("\r|\n", " ") + "' 'http://localhost:8080" + uri + "'");
var after= StringUtils.substringAfter(uri,LISTENER_URL_PREFIX);
var exchange=StringUtils.substringBefore(after,"/");
var topic = StringUtils.substringAfterLast(after, "/");
amqpTemplate.convertAndSend(exchange, topic, body);
servletResponse.setCharacterEncoding(Charsets.UTF_8.toString());
servletResponse.setContentType("application/json;charset=utf-8");
try (ServletOutputStream os = servletResponse.getOutputStream()) {
os.write(SUCCESS.getBytes(Charsets.UTF_8));
}
}
}
}
MessageConverter
由于我们发送的消息是json格式的string而不是对象,所以需要自定义序列化,将json格式String原样所为payload
@Bean
@Primary
public MessageConverter messageConverter(){
return new MessageConverter() {
@Override
public Message toMessage(Object object, MessageProperties messageProperties){
messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
return new Message(object.toString().getBytes(Charsets.UTF_8),messageProperties);
}
@Override
public Object fromMessage(Message message) throws MessageConversionException {
throw new UnsupportedOperationException();
}
};
}
exchange
虽然上面是根据uri来判断发向哪个exchange,但是最好能明确exchang从而自动创建
@Bean
TopicExchange exchange(){
return ExchangeBuilder.topicExchange(EXCHANGE).durable(true).build();
}