技术分享
消息队列的使用
业务场景
需要实现文件导出功能,由于ribbon的接口时间限制,故采用异步的方式进行文件导出。
实现逻辑
接口的主流程不执行数据的操作,将数据的查询和封装操作进行异步处理(时间主要消耗在这一部分)。
rabbitmq实现方式,将数据导出操作的消息推送到队列,然后等待消息被消费即可。最终消费者异步进行数据导出操作,并将结果以邮件的形式发送给用户。
demo
生产者
配置ConnectFactory RabbitTemplate
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true);
return connectionFactory;
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//必须是prototype类型
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(connectionFactory());
return template;
}
交换机的配置可以再配置文件中配置也可以手动在rabbitmq web控制台配置
生产者可以配置相应的回调,得注意rabbittemplate需要是原型模式
public void sendMsg(String content) {
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
//把消息放入ROUTINGKEY_A对应的队列当中去,对应的是队列A
rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_A, RabbitmqConfig.ROUTINGKEY_A, content, correlationId);
}
消费者
监听相应的队列即可@RabbitListener
同时在消费者方法中也可以进行手动确认(需要开启手动确认的配置不然报错)
@RabbitListener(queues = RabbitmqConfig.QUEUE_A)
public void customer(String msg) throws InterruptedException {
log.info("消费的消息:{}",msg);
log.info("开始数据处理。。。。。。。");
Thread.sleep(5000);
log.info("处理完毕");
log.info("发送邮件");
}
@RabbitListener(queues = RabbitmqConfig.QUEUE_A)
public void customerAck(String msg, Message message, Channel channel) throws IOException {
channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
}
参数校验
问题
一般在代码中存在大量的if判断来校验参数的合法性,增加代码复杂度同时又不利于阅读,其实可以通过注解的方式对字段进行校验。
使用
常用
@notEmpty 字段不能为null和空
@pattern 正则校验字符串
定义controller层的参数校验异常统一处理
@RestControllerAdvice
public class ControllerAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public List<ObjectError> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
// 从异常对象中拿到ObjectError对象
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
return allErrors ;
}
}
java8中的流和lambda表达式
@Slf4j
public class StreamTest {
@Test
public void streamTest(){
List<String> list = this.list();
List<List<String>> lists = this.listFlat();
log.info("所有元素处理前{}",list);
List<String> collect = list.stream().map(
e -> {
e = e + "1";
return e;
}
).collect(Collectors.toList());
log.info("所有元素处理后{}",collect);
log.info("原有结构{}",lists);
List<String> collect1 = lists.stream().flatMap(List::stream).collect(Collectors.toList());
log.info("现有结构{}",collect1);
}
public List<String> list(){
ArrayList<String> messageDtos = new ArrayList<>();
for (int i = 0; i < 5; i++) {
messageDtos.add(String.valueOf(i)) ;
}
return messageDtos ;
}
public List<List<String>> listFlat(){
ArrayList<List<String>> lists = new ArrayList<>();
for (int i = 0; i < 5; i++) {
lists.add(this.list());
}
return lists ;
}
}
optional.ofnullable().ifpresent()可以避免操作对象产生空指针的问题