参考资料
一. 前期准备
1.1 标记邮箱种类的接口
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MailCategoryAnnotation {
String mailCode();
}
1.2 邮箱类型区分类
- 考虑到之后可能会有其他类型的区分,因此使用了
内部class
public final class CategoryKbn {
// 邮件种类
public final class MailCategory {
public final static String Mail_163 = "1";
public final static String Mail_QQ = "2";
public final static String Mail_G = "3";
public final static String Mail_OutLook = "4";
}
// 其他种类。。。
}
1.3 入参Form实体类
import lombok.Data;
@Data
public class Test27Form {
// 用于标记邮箱的种类
private String category;
}
二. 邮件发送的业务聚合类
- 自定义的注解作用在Method上,用来标记邮件发送方法的类型
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class SendMailService {
@MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_QQ)
public void sendQQMail(Map<String, String> mailInfoMap) {
System.out.println("QQ邮箱发送邮件。。。");
System.out.println(mailInfoMap);
}
@MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_163)
public void send163Mail(Map<String, String> mailInfoMap) {
System.out.println("163邮箱发送邮件。。。");
System.out.println(mailInfoMap);
}
@MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_G)
public void sendGMail(Map<String, String> mailInfoMap) {
System.out.println("GMail邮箱发送邮件。。。");
System.out.println(mailInfoMap);
}
@MailCategoryAnnotation(mailCode = CategoryKbn.MailCategory.Mail_OutLook)
public void sendOutLookMail(Map<String, String> mailInfoMap) {
System.out.println("OutLook邮箱发送邮件。。。");
System.out.println(mailInfoMap);
}
}
三. 定义函数式接口,创建邮件发送的Map
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Service
public class Test27Service implements InitializingBean {
@Autowired
private SendMailService mailService;
/*
邮件种类code和发送邮件方法的映射Map
*/
private final Map<String, MailFunction<Map<String, String>>> strategySendMailMap = new HashMap<>();
// 标记此接口为函数式编程接口
@FunctionalInterface
interface MailFunction<T> {
// 不知道参数会是什么类型,就使用了泛型
void sendMail(T mailInfo) throws Exception;
}
@Override
public void afterPropertiesSet() throws Exception {
for (Method mailSendMethod : Arrays.asList(mailService.getClass().getMethods())) {
// 如果该方法上没有被标记MailCategoryAnnotation自定义注解就跳过
if (!mailSendMethod.isAnnotationPresent(MailCategoryAnnotation.class)) {
continue;
}
// 获取Method上被标记的MailCategoryAnnotation注解上的mailCode
String mailCode = mailSendMethod.getAnnotation(MailCategoryAnnotation.class).mailCode();
// 将mailcode和发送邮件的方法添加到Map中
strategySendMailMap.put(mailCode, (T) -> mailSendMethod.invoke(mailService, T));
}
}
public void execute(String category) throws Exception {
// 发送邮件时所需要的参数
Map<String, String> mailInfoMap = new HashMap<>() {
{
put("id", "110120");
put("name", "jiafeitian");
}
};
// 根据category获取邮件的发送方法,并执行
MailFunction<Map<String, String>> sendMailFunction = strategySendMailMap.get(category);
sendMailFunction.sendMail(mailInfoMap);
}
}
四. 效果
⏹前台
const jsonData = {
category: '2'
};
$.ajax({
url: "/test27/test1",
type: 'POST',
data: JSON.stringify(jsonData),
contentType: 'application/json;charset=utf-8',
success: function (data, status, xhr) {
console.log(data);
}
});
⏹后台
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
@PostMapping("/test1")
public ResponseEntity<Void> test1(@RequestBody Test27Form form) throws Exception {
service.execute(form.getCategory());
return ResponseEntity.noContent().build();
}
👇效果
五. 小结
上述的简化if else
的方法本质上使用了函数式编程中的Consumer
消费方法,该方法可放到Map中进行映射,可根据Map中的key动态灵活的执行方法,从而减少分支。
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import javax.annotation.PostConstruct;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Controller;
@Controller
public class ConsumerTestController implements CommandLineRunner {
// 定义code和Consumer消费方法的映射
private final Map<String, Consumer<String>> strategySendMailMap = new HashMap<>();
@PostConstruct
private void init() {
// 定义了一个消费方法,对传入的参数str进行消费,消费方法无返回值
Consumer<String> printInfo1 = (String str) -> {
System.out.println(str);
System.out.println("printInfo1");
};
Consumer<String> printInfo2 = (String str) -> {
System.out.println(str);
System.out.println("printInfo2");
};
// 类似于JavaScript中的Map映射
strategySendMailMap.put("a", printInfo1);
strategySendMailMap.put("b", printInfo2);
/*
相当于这种写法的简写模式
strategySendMailMap.put("c", (String str) -> ConsumerTestController.printInfo3(str));
*/
strategySendMailMap.put("c", ConsumerTestController::printInfo3);
}
@Override
public void run(String... args) throws Exception {
// 模拟根据参数然后从Map映射中获取消费函数
Consumer<String> consumer = strategySendMailMap.get("c");
// 传入参数,执行消费函数
consumer.accept("你好");
}
public static void printInfo3(String str) {
System.out.println(str);
System.out.println("printInfo3");
}
}