https://juejin.im/post/5cb880c2f265da03981fc031
一.说明
我们在使用SpringBoot的时候常常要引入一些Starter,例如spring-boot-starter-web,官方为我们提供了几乎所有的默认配置,很好的降低了使用框架时的复杂度,所以在用xxx-starter的时候,可以不用费心去写一些繁琐的配置文件,即使必要的配置在application.properties或application.yml中配置就可以了,当你实现了一个Starter,可以在不同的项目中复用,非常方便,今天我们来编写自己的Starter以之前的短信业务为例。
Springboot短信业务调用:juejin.im/post/5cb165…
spring-boot-starter-xxx是官方提供Starter的命名规则,非官方Starter的命名规则官方建议为 xxx-spring-boot-starter
二.搭建项目
建立SpringBoot项目,清除resources下的文件和文件夹
Maven依赖如下: <dependencies>
<!--封装Starter核心依赖 -->
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.1.3.RELEASE</version> </dependency> <!--非必需,该依赖作用是在使用IDEA编写配置文件有代码提示--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.1.3.RELEASE</version> </dependency> <!-- lombok 插件 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.6</version> <optional>true</optional> </dependency> <!-- 因为要使用RestTemplate和转换Json,所以引入这两个依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.3.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.45</version> </dependency> </dependencies> 复制代码
spring-boot-configuration-processor不是必须的,它的作用是和编译时生成 spring-configuration-metadata.json,此文件主要给IDEA使用.配置此JAR相关配置属性在 application.yml中,你可以用Ctrl+鼠标左键点击属性名,IDE会跳转到你配置此属性的类中.并且编写application.yml会有代码提示.
二.编写项目基础类
创建SendSMSDTO传输类,用于参数传递
/**
* SMSDTO参数类
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
@Data public class SendSMSDTO { /** * 模板ID */ private String templateid; /** * 参数 */ private String param; /** * 手机号 */ private String mobile; /** * 用户穿透ID,可以为空 */ private String uid; } 复制代码
创建RestTemplateConfig配置类,用于调用短信接口
/**
* RestTemplateConfig配置
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
@Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate( ) { return new RestTemplate(); } } 复制代码
创建短信接口枚举类,用于存放短信接口API地址
/**
* 短信请求API枚举
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
@Getter public enum ENUM_SMSAPI_URL { SENDSMS("https://open.ucpaas.com/ol/sms/sendsms"), SENDBATCHSMS("https://open.ucpaas.com/ol/sms/sendsms_batch"); private String url; ENUM_SMSAPI_URL(String url) { this.url = url; } } 复制代码
三.编写Starter自动配置类
创建SmsProperties配置属性类,该类主要用于读取yml/properties信息
/**
* SMS配置属性类
* @Author Sans
* @CreateTime 2019/4/20
* @attention 使用ConfigurationProperties注解可将配置文件(yml/properties)中指定前缀的配置转为bean
*/
@Data @ConfigurationProperties(prefix = "sms-config") public class SmsProperties { private String appid; private String accountSid; private String authToken; } 复制代码
创建短信核心服务类
/**
* 短信核心服务类
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
public class SmsService { @Autowired private RestTemplate restTemplate; private String appid; private String accountSid; private String authToken; /** * 初始化 */ public SmsService(SmsProperties smsProperties) { this.appid = smsProperties.getAppid(); this.accountSid = smsProperties.getAccountSid(); this.authToken = smsProperties.getAuthToken(); } /** * 单独发送 */ public String sendSMS(SendSMSDTO sendSMSDTO){ JSONObject jsonObject = new JSONObject(); jsonObject.put("sid", accountSid); jsonObject.put("token", authToken); jsonObject.put("appid", appid); jsonObject.put("templateid", sendSMSDTO.getTemplateid()); jsonObject.put("param", sendSMSDTO.getParam()); jsonObject.put("mobile", sendSMSDTO.getMobile()); if (sendSMSDTO.getUid()!=null){ jsonObject.put("uid",sendSMSDTO.getUid()); }else { jsonObject.put("uid",""); } String json = JSONObject.toJSONString(jsonObject); //使用restTemplate进行访问远程Http服务 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); HttpEntity<String> httpEntity = new HttpEntity<String>(json, headers); String result = restTemplate.postForObject(ENUM_SMSAPI_URL.SENDSMS.getUrl(), httpEntity, String.class); return result; } /** * 群体发送 */ public String sendBatchSMS(SendSMSDTO sendSMSDTO){ JSONObject jsonObject = new JSONObject(); jsonObject.put("sid", accountSid); jsonObject.put("token", authToken); jsonObject.put("appid", appid); jsonObject.put("templateid", sendSMSDTO.getTemplateid()); jsonObject.put("param", sendSMSDTO.getParam()); jsonObject.put("mobile", sendSMSDTO.getMobile()); if (sendSMSDTO.getUid()!=null){ jsonObject.put("uid",sendSMSDTO.getUid()); }else { jsonObject.put("uid",""); } String json = JSONObject.toJSONString(jsonObject); //使用restTemplate进行访问远程Http服务 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); HttpEntity<String> httpEntity = new HttpEntity<String>(json, headers); String result = restTemplate.postForObject(ENUM_SMSAPI_URL.SENDBATCHSMS.getUrl(), httpEntity, String.class); return result; } } 复制代码
创建SmsAutoConfiguration自动配置类,该类主要用于创建核心业务类实例
/**
* 短信自动配置类
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
@Configuration @EnableConfigurationProperties(SmsProperties.class)//使@ConfigurationProperties注解生效 public class SmsAutoConfiguration { @Bean public SmsService getBean(SmsProperties smsProperties){ SmsService smsService = new SmsService(smsProperties); return smsService; } } 复制代码
四.创建spring.factories文件
spring.factories该文件用来定义需要自动配置的类,SpringBoot启动时会进行对象的实例化,会通过加载类SpringFactoriesLoader加载该配置文件,将文件中的配置类加载到spring容器
在src/main/resources新建META-INF文件夹,在META-INF文件夹下新建spring.factories文件.配置内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sms.starter.config.SmsAutoConfiguration
复制代码
五.打包和测试
使用Maven插件,将项目打包安装到本地仓库
新建测试项目,引入我们自己的Starter,Maven依赖如下:<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 添加我们自己的starter--> <dependency> <groupId>com.sms.starter</groupId> <artifactId>sms-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> 复制代码
配置测试项目的application.yml
sms-config:
account-sid: //这里填写平台获取的ID和KEY
auth-token: //这里填写平台获取的ID和KEY appid: //这里填写平台获取的ID和KEY 复制代码
参数填写自己的手机号和申请的模板以及对应的参数
/**
* 测试短信DEMO
* @Author Sans
* @CreateTime 2019/4/20
* @attention
*/
@RestController @RequestMapping("/sms") public class TestController { @Autowired private SmsService smsService; /** * 短信测试 * @Attention * @Author: Sans * @CreateTime: 2019/4/20 */ @RequestMapping(value = "/sendsmsTest",method = RequestMethod.GET) public String sendsmsTest(){ //创建传输类设置参数 SendSMSDTO sendSMSDTO = new SendSMSDTO(); sendSMSDTO.setMobile(""); //手机号 sendSMSDTO.setTemplateid(""); //模板 sendSMSDTO.setParam(""); //参数 return smsService.sendSMS(sendSMSDTO); } } 复制代码
六.后续补充
在引入自己封装的Starter的时候,有的人会报错****类的bean没有找到问题,是因为@SpringBootApplication扫描包的范围是启动类所在同级包和子包,但是不包括第三方的jar包.如果需要扫描maven依赖添加的Jar,我们就要单独使用@ComponentScan注解扫描包. 针对这种情况解决方式有两种:
第一种:是你封装的Starter项目下父级包名称和测试项目的父级包名一样,例如这两个项目包名都叫com.sans,这样可以不使用@ComponentScan注解,很显然这样做有局限性,不推荐.
第二种:是可以单独使用@ComponentScan注解扫描第三方包,但是这里一定要注意@SpringBootApplication注解等价于默认属性使用@Configuration+@EnableAutoConfiguration+@ComponentScan,如果@SpringBootApplication和@ComponentScan注解同时存在,那么@SpringBootApplication注解中@ComponentScan的扫描范围会被覆盖,所以单独使用@ComponentScan的话,必须在该注解上配置项目需要扫描的包的所有范围,即项目包路径+依赖包路径.
/**
* @ComponentScan注解扫描多个包下示例
*/
@ComponentScan({"com.test","sms.test"}) 复制代码
项目源码: gitee.com/liselotte/s…
深夜发帖,十分不易,希望大佬们提出宝贵意见
作者:Sans_
链接:https://juejin.im/post/5cb880c2f265da03981fc031
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。