A. Instructions

We often use SpringBoot to introduce some Starter, such as spring-boot-starter-web, the official provides us with almost all the default configuration, very good to reduce the complexity of using the framework, so when using XXX-starter, you can not bother to write Some cumbersome configuration files, even the necessary configuration in application. Properties or application. Yml can be configured, when you implement a Starter, can be reused in different projects, very convenient, today we will write our own Starter to the previous SMS industry Service as an example.

Call the Springboot SMS service: juejin.cn/post/684490…

Spring-boot-starter-xxx indicates the official naming rule for the starter. The unofficial naming rule is recommended as XXx-spring-boot-starter

Ii. Construction project

Set up the SpringBoot project and clear files and folders under Resources

 <dependencies>
        <! Encapsulating the Starter core dependency
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>2.1.3. RELEASE</version>
        </dependency>
        <! -- Not required, this dependency is used when writing configuration files using IDEA.
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.1.3. RELEASE</version>
        </dependency>
        <! -- Lombok plugin -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
            <optional>true</optional>
        </dependency>
        <! Since we are going to use RestTemplate and transform Json, we introduce these two dependencies -->
        <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>
Copy the code

Spring-boot-configuration-processor is not required. It generates spring-configuration-metadata.json during compilation. This file is used for IDEA. In application. Yml, you can press Ctrl+ left mouse button on the property name and the IDE will jump to the class for which you configured the property. And there are code prompts for writing application.yml.

Two. Write the project base class

Create the SendSMSDTO transport class for parameter passing

/** * SMSDTO argument class *@Author Sans
 * @CreateTime 2019/4/20 
 * @attention* /
@Data
public class SendSMSDTO {
    /** * template ID */
    private String templateid;
    /** * parameter */
    private String param;
    /** * Mobile phone number */
    private String mobile;
    /** * User penetration ID, can be empty */
    private String uid;
}
Copy the code

Create the RestTemplateConfig configuration class to invoke the SMS interface

/** * RestTemplateConfig configuration *@Author Sans
 * @CreateTime 2019/4/20 
 * @attention* /
@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate( ) {
        return newRestTemplate(); }}Copy the code

Create an SMS interface enumeration class to store the SMS API addresses

/** * SMS request API enumeration *@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; }}Copy the code

Write the Starter auto-configuration class

Create the SmsProperties configuration property class, which is used to read YML/Properties information

/** * SMS config attribute class *@Author Sans
 * @CreateTime 2019/4/20 
 * @attentionUse the ConfigurationProperties annotation to convert the configuration of the specified prefix in the configuration file (YML/Properties) to bean */
@Data
@ConfigurationProperties(prefix = "sms-config")
public class SmsProperties {
    private String appid;
    private String accountSid;
    private String authToken;
}
Copy the code

Create a core SMS service class

/** * SMS core services *@Author Sans
 * @CreateTime 2019/4/20 
 * @attention* /
public class SmsService {

    @Autowired
    private RestTemplate restTemplate;
    private String appid;
    private String accountSid;
    private String authToken;

    /** * initializes */
    public SmsService(SmsProperties smsProperties) {
       this.appid = smsProperties.getAppid();
       this.accountSid = smsProperties.getAccountSid();
       this.authToken = smsProperties.getAuthToken();
    }

    /** ** send */ separately
    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);
        // Use restTemplate to access the remote Http service
        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;
    }

    /** * group sends */
    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);
        // Use restTemplate to access the remote Http service
        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);
        returnresult; }}Copy the code

Create the SmsAutoConfiguration automatic configuration class, which is used to create instances of core business classes

/** * SMS automatic configuration class *@Author Sans
 * @CreateTime 2019/4/20 
 * @attention* /
@Configuration  
@EnableConfigurationProperties(SmsProperties.class)// Enable the @configurationProperties annotation
public class SmsAutoConfiguration {
    @Bean
    public SmsService getBean(SmsProperties smsProperties){
        SmsService smsService = new SmsService(smsProperties);
        returnsmsService; }}Copy the code

Create the Spring. factories file

The spring.factories file is used to define the classes that need to be configured automatically. When SpringBoot starts, the objects are instantiated and the configuration file is loaded by loading the SpringFactoriesLoader class

Create a new meta-INF folder in SRC /main/resources and a new spring.factories file in the meta-INF folder. The configuration is as follows:

 org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.sms.starter.config.SmsAutoConfiguration
Copy the code

Package and test

Using the Maven plug-in, package the project and install it into a local repository

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <! -- Add our own starter-->
        <dependency>
            <groupId>com.sms.starter</groupId>
            <artifactId>sms-spring-boot-starter</artifactId>
            <version>0.0.1 - the SNAPSHOT</version>
        </dependency>
</dependencies>
Copy the code

Configure the application. Yml of the test project

sms-config:
  account-sid:  // Enter the ID and KEY obtained by the platform
  auth-token:   // Enter the ID and KEY obtained by the platform
  appid:        // Enter the ID and KEY obtained by the platform
Copy the code

Parameter Enter your mobile phone number, application template, and corresponding parameters

/** * Test SMS DEMO *@Author Sans
 * @CreateTime 2019/4/20 
 * @attention* /
@RestController
@RequestMapping("/sms")
public class TestController {
    @Autowired
    private SmsService smsService;
    /** * SMS test *@Attention
     * @Author: Sans
     * @CreateTime: 2019/4/20 * /
    @RequestMapping(value = "/sendsmsTest",method = RequestMethod.GET)
    public String sendsmsTest(a){
        // Create transport class Settings parameters
        SendSMSDTO sendSMSDTO  = new SendSMSDTO();
        sendSMSDTO.setMobile("");     / / cell phone number
        sendSMSDTO.setTemplateid(""); / / template
        sendSMSDTO.setParam("");      / / parameters
        returnsmsService.sendSMS(sendSMSDTO); }}Copy the code

Vi. Follow-up supplement

Some people will report an error when introducing their own packaged Starter bean (****) because @SpringBootApplication scans for the same class and subclass of the Starter class, but does not include third-party JAR packages. If we need to scan jars added by Maven dependencies, we use the @ComponentScan annotation alone to scan the package. There are two solutions to this situation:

The first is that the parent package name of the Starter project you encapsulate is the same as the parent package name of the test project. For example, the parent package name of both projects is com.sans. This allows you to avoid using the @ComponentScan annotation.

It is possible to use the @ComponentScan annotation alone to scan third-party packages, but it is important to note that the @SpringBootApplication annotation is equivalent to the default attribute @Configuration+ @enableAutoConfiguration + @com PonentScan, if @SpringBootApplication and @ComponentScan annotations exist together, The @SpringBootApplication annotation will overwrite the scope of the @ComponentScan scan, so using @ComponentScan alone, the annotation must be configured with all the scope of the package that the project needs to scan, that is, the project package path + the dependency package path.

/ * * *@ComponentScanAnnotations scan multiple packages under the example */
@ComponentScan({"com.test"."sms.test"})
Copy the code

Project source: gitee.com/liselotte/s…

Late night post, very not easy, hope big guy people put forward valuable opinion