返回顶部
首页 > 资讯 > 精选 >SpringBoot集成短信和邮件的配置方法
  • 150
分享到

SpringBoot集成短信和邮件的配置方法

2023-06-30 08:06:57 150人浏览 独家记忆
摘要

本文小编为大家详细介绍“SpringBoot集成短信和邮件的配置方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“springBoot集成短信和邮件的配置方法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。准备工

本文小编为大家详细介绍“SpringBoot集成短信和邮件的配置方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“springBoot集成短信和邮件的配置方法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

准备工作

1、集成邮件

以QQ邮箱为例

在发送邮件之前,要开启POP3和SMTP协议,需要获得邮件服务器的授权码,获取授权码:

设置>账户

在账户的下面有一个开启SMTP协议的开关并进行密码验证:

SpringBoot集成短信和邮件的配置方法

获取成功的授权码

SpringBoot集成短信和邮件的配置方法

2、集成短信

阿里云短信服务为例

登陆阿里云—>进入控制台—>开通短信服务

进入后根据提示开通短信服务即可。

充值

后期发短信测试需要,暂时可以跳过此步骤。

获取AccessKey和AccessSercet

api

依赖

邮件

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-mail</artifactId></dependency>

短信

<dependency>    <groupId>com.aliyun</groupId>    <artifactId>dysmsapi20170525</artifactId>    <version>2.0.4</version></dependency>

配置

配置邮箱基本信息

spring:  mail:    # 配置 SMTP 服务器地址    host: smtp.qq.com    # 发送者邮箱    username: 742354529@qq.com    # 配置密码,注意不是真正的密码,而是申请的授权码    passWord: vjstfghblprwbdbd    # 端口号465或587    port: 587     # 默认的邮件编码为UTF-8    default-encoding: UTF-8    # 配置SSL 加密工厂    properties:      mail:        smtp:          SocketFactoryClass: javax.net.ssl.SSLSocketFactory        # 表示开启DEBUG模式,邮件发送过程的日志会在控制台打印出来        debug: true

SMTP 服务器地址

  • 126邮箱SMTP服务器地址:smtp.126.com,端口号:465或者994

  • 2163邮箱SMTP服务器地址:smtp.163.com,端口号:465或者994

  • yeah邮箱SMTP服务器地址:smtp.yeah.net,端口号:465或者994

  • qq邮箱SMTP服务器地址:smtp.qq.com,端口号465或587*

短信配置

# 阿里云短信配置sms:  access-id: LTAI5tDP3SDQC9yvCguiiFDr  access-key: EGSDQsLxCVS5dwjS8DCxmYQ124XySV  sign-name:   endpoint: dysmsapi.aliyuncs.com

编码

1、邮件

1、MailService.java

package com.tanersci.service;import com.tanersci.dto.MailMessageDto;import com.tanersci.vo.MessageVo;public interface MailService {MessageVo sendSimple(MailMessageDto dto); * @MonthName: sendAttachFile * @Description: 带附件的邮件MessageVo sendAttachFile(MailMessageDto dto); * @MonthName: sendImgRes * @Description: 带图片资源的邮件MessageVo sendImgRes(MailMessageDto dto);}

2、MailServiceImpl.java

package com.tanersci.service.impl;import com.alibaba.fastJSON.JSON;import com.tanersci.dto.MailMessageDto;import com.tanersci.vo.MessageVo;import com.tanersci.constant.Constants;import com.tanersci.service.MailService;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.core.io.FileSystemResource;import org.springframework.mail.MailException;import org.springframework.mail.SimpleMailMessage;import org.springframework.mail.javamail.JavaMailSender;import org.springframework.mail.javamail.MimeMessageHelper;import org.springframework.stereotype.Service;import javax.mail.MessagingException;import javax.mail.internet.MimeMessage;import java.time.LocalDateTime;import java.util.Date;import java.util.Objects;@Slf4j@Servicepublic class MailServiceImpl implements MailService {@Value("${spring.mail.username}")private String sender;@Autowiredprivate JavaMailSender javaMailSender;@Overridepublic MessageVo sendSimple(MailMessageDto dto) {try {log.info("=======普通邮件发送开始,请求参数:{}", JSON.toJSON(dto));// 构建一个邮件对象SimpleMailMessage message = new SimpleMailMessage();// 设置邮件主题message.setSubject(dto.getSubject());// 设置邮件发送者,这个跟application.yml中设置的要一致message.setFrom(sender);// 设置邮件接收者,可以有多个接收者,中间用逗号隔开,以下类似// message.setTo("10*****16@qq.com","12****32*qq.com");message.setTo(dto.getRecipient());// 设置邮件抄送人,可以有多个抄送人if (Objects.nonNull(dto.getCc())) {message.setCc(dto.getCc());}// 设置隐秘抄送人,可以有多个if (Objects.nonNull(dto.getBcc())) {message.setBcc(dto.getBcc());// 设置邮件发送日期message.setSentDate(new Date());// 设置邮件的正文message.setText(dto.getText());// 发送邮件javaMailSender.send(message);log.info("=======普通邮件发送结束");return MessageVo.builder().code(Constants.NEWS_SUCCESS_CODE).message(Constants.NEWS_SUCCESS_MESSAGE).build();} catch (MailException e) {log.error("====邮件====sendSimple=====异常:{}", e);return MessageVo.builder().code(Constants.NEWS_FAIL_CODE).message(Constants.NEWS_FAIL_MESSAGE).build();}} * @MonthName: sendAttachFile * @Description: 带附件的邮件public MessageVo sendAttachFile(MailMessageDto dto) {log.info("=======带附件的邮件开始,请求参数:{}", JSON.toJSON(dto));MimeMessage mimeMessage = javaMailSender.createMimeMessage();// true表示构建一个可以带附件的邮件对象MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true);// 第一个参数是自定义的名称,后缀需要加上,第二个参数是文件的位置dto.getAttachments().forEach(file -> {try {message.addAttachment(file.getName(), file);} catch (MessagingException e) {log.error("=========邮件附件解析异常:{}", e);}});javaMailSender.send(mimeMessage);log.info("=======带附件的邮件结束");} catch (MessagingException e) {log.error("==========邮件====sendAttachFile=====异常:{}", e); * @MonthName: sendImgRes * @Description: 带图片资源的邮件public MessageVo sendImgRes(MailMessageDto dto) {log.info("=======带图片资源的邮件开始,请求参数:{}", JSON.toJSON(dto));// 第一个参数指的是html中占位符的名字,第二个参数就是文件的位置message.addInline(file.getName(), new FileSystemResource(file));log.error("=========邮件图片解析异常:{}", e);log.info("=======带图片资源的邮件结束");log.error("====邮件====sendImgRes=====异常:{}", e);}

3、VO、DTO及常量类

MailMessageDto.java

package com.tanersci.dto;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.File;import java.io.Serializable;import java.util.List;@Data@AllArgsConstructor@NoArgsConstructor@Builder@ApiModel(value = "邮件消息")public class MailMessageDto implements Serializable {private static final long serialVersionUID = 5483400172436286831L;@ApiModelProperty(value = "邮件主题")private String subject;@ApiModelProperty(value = "接收者:可以有多个接收者,中间用逗号隔开")private String recipient;@ApiModelProperty(value = "抄送人:可以有多个抄送人,中间用逗号隔开")private String cc;@ApiModelProperty(value = "隐秘抄送人:可以有多个抄送人,中间用逗号隔开")private String bcc;@ApiModelProperty(value = "正文")private String text;@ApiModelProperty(value = "模板编码")private String code;@ApiModelProperty(value = "附件、图片")private List<File> attachments;}

MessageVo.java

package com.tanersci.vo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;@Data@AllArgsConstructor@NoArgsConstructor@Builder@ApiModel(value = "短信、邮件消息返回值")public class MessageVo implements Serializable {private static final long serialVersionUID = 5287525465339500144L;@ApiModelProperty(value = "状态码")private String code;@ApiModelProperty(value = "状态码的描述")private String message;@ApiModelProperty(value = "请求ID")private String requestId;@ApiModelProperty(value = "发送回执ID")private String bizId;@ApiModelProperty(value = "模板编码")private String templateCode;}

Constants.java

package com.tanersci.constant;public class Constants {public final static String NEWS_SUCCESS_CODE = "OK";public final static String NEWS_SUCCESS_MESSAGE = "发送成功";public final static String NEWS_FAIL_CODE = "FAIL";public final static String NEWS_FAIL_MESSAGE = "发送失败";}
2、短信

1、SmsService.java

package com.tanersci.service;import com.tanersci.dto.SmsMessageDto;import com.tanersci.dto.SmsTemplateDto;import com.tanersci.vo.MessageVo;public interface SmsService {MessageVo send(SmsMessageDto dto); * @MonthName: addSmsTemplate * @Description: 申请短信模板 * @Param: [template]MessageVo addSmsTemplate(SmsTemplateDto template); * @MonthName: deleteSmsTemplate * @Description: 删除短信模板MessageVo deleteSmsTemplate(SmsTemplateDto template); * @MonthName: modifySmsTemplate * @Description: 修改未通过审核的短信模板MessageVo modifySmsTemplate(SmsTemplateDto template); * @MonthName: querySmsTemplate * @Description: 查询短信模板的审核状态MessageVo querySmsTemplate(SmsTemplateDto template);}

2、SmsServiceImpl.java

package com.tanersci.service.impl;import com.alibaba.fastjson.JSON;import com.aliyun.dysmsapi20170525.Client;import com.aliyun.dysmsapi20170525.models.*;import com.aliyun.teaopenapi.models.Config;import com.tanersci.dto.SmsMessageDto;import com.tanersci.dto.SmsTemplateDto;import com.tanersci.vo.MessageVo;import com.tanersci.config.SmsConfig;import com.tanersci.constant.Constants;import com.tanersci.service.SmsService;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.time.LocalDateTime;import java.util.Objects;import java.util.UUID;@Slf4j@Servicepublic class SmsServiceImpl implements SmsService {@Autowiredprivate SmsConfig smsConfig;public Client createClient() throws Exception {Config config = new Config();config.accessKeyId = smsConfig.getAccessId();config.accessKeySecret = smsConfig.getAccessKey();config.endpoint = smsConfig.getEndpoint();return new Client(config);} * @MonthName: send * @Description: 发短信 * @Date: 2021/6/7 14:50 * @Param: [dto] * @return: com.tanersci.vo.MessageVo@Overridepublic MessageVo send(SmsMessageDto dto) {try {log.info("======发送短信开始,请求参数:{}", JSON.toJSON(dto));Client client = createClient();// 组装请求对象SendSmsRequest request = new SendSmsRequest();// 外部流水扩展字段String outId = UUID.randomUUID().toString();request.setOutId(outId);// 支持对多个手机号码发送短信,手机号码之间以英文逗号(,)分隔。上限为1000个手机号码。批量调用相对于单条调用及时性稍有延迟。request.setPhoneNumbers(dto.getPhone());// 短信签名名称request.setSignName(smsConfig.getSignName());// 短信模板IDrequest.setTemplateCode(dto.getTemplateCode());// 短信模板变量对应的实际值,JSON格式。如果JSON中需要带换行符,请参照标准的JSON协议处理。request.setTemplateParam(JSON.toJSONString(dto.getParam()));// 发送短信SendSmsResponse res = client.sendSms(request);MessageVo message = MessageVo.builder().build();if (Objects.equals(Constants.NEWS_SUCCESS_CODE, res.body.getCode())) {log.info("======发送短信成功,返回值:{}", JSON.toJSON(res.body));message.setCode(Constants.NEWS_SUCCESS_CODE);message.setMessage(Constants.NEWS_SUCCESS_MESSAGE);} else {log.info("======发送短信失败,返回值:{}", JSON.toJSON(res.body));message.setCode(Constants.NEWS_FAIL_CODE);message.setMessage(Constants.NEWS_FAIL_MESSAGE);}return message;} catch (Exception e) {log.error("======发送短信异常:{}", e.getMessage());e.printStackTrace();return MessageVo.builder().code(Constants.NEWS_FAIL_CODE).message(Constants.NEWS_FAIL_MESSAGE).build();} * @MonthName: addSmsTemplate * @Description: 申请短信模板 * @Param: [template]public MessageVo addSmsTemplate(SmsTemplateDto template) {log.info("======申请短信模板,请求参数:{}", JSON.toJSON(template));AddSmsTemplateRequest request = new AddSmsTemplateRequest();request.setTemplateType(template.getTemplateType());request.setTemplateName(template.getTemplateName());request.setTemplateContent(template.getTemplateContent());request.setRemark(template.getRemark());AddSmsTemplateResponse res = client.addSmsTemplate(request);if (Objects.equals(TeamConstants.NEWS_SUCCESS_CODE, res.body.getCode())) {log.info("======申请短信模板,返回值:{}", JSON.toJSON(res.body));return MessageVo.builder().code(Constants.NEWS_SUCCESS_CODE).message(Constants.NEWS_SUCCESS_MESSAGE).templateCode(res.getBody().templateCode).build();return MessageVo.builder().code(Constants.NEWS_FAIL_CODE).message(Constants.NEWS_FAIL_MESSAGE).build();log.error("======申请短信模板,异常:{}", e.getMessage()); * @MonthName: deleteSmsTemplate * @Description: 删除短信模板public MessageVo deleteSmsTemplate(SmsTemplateDto template) {log.info("======删除短信模板,请求参数:{}", JSON.toJSON(template));DeleteSmsTemplateRequest request = new DeleteSmsTemplateRequest();request.setTemplateCode(template.getTemplateCode());DeleteSmsTemplateResponse res = client.deleteSmsTemplate(request);log.info("======删除短信模板,返回值:{}", JSON.toJSON(res.body));return MessageVo.builder().code(Constants.NEWS_SUCCESS_CODE).message(Constants.NEWS_SUCCESS_MESSAGE).build();log.error("======删除短信模板,异常:{}", e); * @MonthName: modifySmsTemplate * @Description: 修改未通过审核的短信模板public MessageVo modifySmsTemplate(SmsTemplateDto template) {log.info("======修改未通过审核的短信模板,请求参数:{}", JSON.toJSON(template));ModifySmsTemplateRequest request = new ModifySmsTemplateRequest();ModifySmsTemplateResponse res = client.modifySmsTemplate(request);log.info("======修改未通过审核的短信模板,返回值:{}", JSON.toJSON(res.body));log.error("======修改未通过审核的短信模板,异常:{}", e.getMessage()); * @MonthName: querySmsTemplate * @Description: 查询短信模板的审核状态public MessageVo querySmsTemplate(SmsTemplateDto template) {log.info("======查询短信模板的审核状态,请求参数:{}", JSON.toJSON(template));QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();QuerySmsTemplateResponse res = client.querySmsTemplate(request);log.info("======查询短信模板的审核状态,返回值:{}", JSON.toJSON(res.body));log.error("======查询短信模板的审核状态,异常:{}", e.getMessage());}

3、SmsConfig.java

package com.tanersci.config;import lombok.Data;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;@Data@Componentpublic class SmsConfig {@Value("${sms.access-id}")private String accessId;@Value("${sms.access-key}")private String accessKey;@Value("${sms.sign-name}")private String signName;@Value("${sms.endpoint}")private String endpoint;}

4、VO、DTO类

MessageVo 同用邮件的

MailMessageDto.java

package com.tanersci.dto;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;@Data@AllArgsConstructor@NoArgsConstructor@Builder@ApiModel(value = "短信消息")public class SmsMessageDto implements Serializable {private static final long serialVersionUID = 3427970548460798908L;@ApiModelProperty(value = "手机号,多个以逗号隔开")private String phone;@ApiModelProperty(value = "模板编码")private String templateCode;@ApiModelProperty(value = "模板参数")private TemplateParamDto param;private String code;}

SmsTemplate.java

package com.tanersci.dto;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;@Data@AllArgsConstructor@NoArgsConstructor@Builderpublic class SmsTemplateDto implements Serializable {private static final long serialVersionUID = -8909531614461840038L;private Integer templateType; * 模板名称,长度为1~30个字符private String templateName; * 模板内容,长度为1~500个字符private String templateContent; * 短信模板CODEprivate String templateCode; * 短信模板申请说明。请在申请说明中描述您的业务使用场景,长度为1~100个字符private String remark;}

注意

项目中使用lombok插件和swagger依赖,无相关依赖的请自行修改。

读到这里,这篇“SpringBoot集成短信和邮件的配置方法”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

--结束END--

本文标题: SpringBoot集成短信和邮件的配置方法

本文链接: https://lsjlt.com/news/327789.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringBoot集成短信和邮件的配置方法
    本文小编为大家详细介绍“SpringBoot集成短信和邮件的配置方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot集成短信和邮件的配置方法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。准备工...
    99+
    2023-06-30
  • SpringBoot 集成短信和邮件的配置示例详解
    目录依赖配置编码1、邮件2、短信准备工作 1、集成邮件 以QQ邮箱为例 在发送邮件之前,要开启POP3和SMTP协议,需要获得邮件服务器的授权码,获取授权码: 1、设置>账户 ...
    99+
    2024-04-02
  • SpringBoot集成slf4j日志配置的方法
    目录前言 1、slf4j概述 2、pom.xml的日志依赖 3、application.yml的日志配置 4、logback.xml配置文件定义 5、logback.xml配置文件解...
    99+
    2024-04-02
  • Springboot集成Jasypt实现配置文件加密的方法
    目录Jasypt介绍Jasypt好处应用场景使用方式实战使用Windows环境变量方式指定Linux环境变量方式进行指定Jasypt介绍 Jasypt是一个java库,它允许开发员以...
    99+
    2023-05-18
    Springboot集成Jasypt Springboot集成Jasypt文件加密
  • 关于springboot集成阿里云短信的问题
    目录1.获取签名与模板2.编写模板与签名的枚举类3.配置类4.测试类​ 1.获取签名与模板 进入阿里云平台,进入短信服务模块,在以下位置添加签名和模板(格式一定按照要求填写 审批的比...
    99+
    2024-04-02
  • springboot集成KoTime的配置过程
    目录koTime功能可视化展示koTime是一个springboot项目性能分析工具,通过追踪方法调用链路以及对应的运行时长快速定位性能瓶颈。 在pom.xml文件中引入 <d...
    99+
    2024-04-02
  • springboot集成dubbo的方法
    这篇“springboot集成dubbo的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springboot集成dubb...
    99+
    2023-06-29
  • SpringBoot集成Mybatis+xml格式的sql配置文件操作
    SpringBoot集成Mybatis+xml格式的sql配置文件 最近一直在研究SpringBoot技术,由于项目需要,必须使用Mybatis持久化数据。所以就用SpringBoo...
    99+
    2024-04-02
  • springboot redis集群配置的方法是什么
    要配置Spring Boot中的Redis集群,可以使用以下方法:1. 添加Redis依赖项:在`pom.xml`文件中添加Spri...
    99+
    2023-09-16
    springboot redis
  • SpringBoot如何解析配置类以及集成第三方配置
    小编给大家分享一下SpringBoot如何解析配置类以及集成第三方配置,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!SpringBoot作为Java领域非常流行的...
    99+
    2023-06-03
  • SpringBoot集成Jasypt敏感信息加密的操作方法
    目录前言哪些信息需要加密敏感信息加密的作用选择加密的组件项目集成Jasypt方式方式一方式二方式三Springboot整合Jasypt实战一、引入依赖二、配置文件中添加Jasypt配...
    99+
    2024-04-02
  • springboot集成elasticsearch7的图文方法
    目录1.创建项目2.创建配置文件3.测试4.更新文档5.删除文档1.创建项目 修改依赖版本 2.创建配置文件 package com.huanmingj...
    99+
    2024-04-02
  • Spring通过Java配置集成Tomcat的方法
    添加Tomcat依赖 <!-- 自己编译的版本--> <dependency> <groupId>org.apache</gro...
    99+
    2024-04-02
  • springboot配置多数据源并集成Druid和mybatis的操作
    可以是mysql,oracle等多种不同数据源 项目结构 注意:只有@Primary的数据源所控制的mapper文件加注解@Mapper,否则mybatis无法切换扫描;即本文中...
    99+
    2024-04-02
  • springboot整合RabbitMQ发送短信的实现方法
    这篇文章主要介绍springboot整合RabbitMQ发送短信的实现方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!RabbitMQ安装和运行# 安装rpm -ivh erlang-...
    99+
    2023-06-15
  • SpringBoot整合阿里云短信服务的方法
    目录一、新建短信微服务1、在service模块下创建子模块service-msm3.配置application.properties4、创建启动类二、阿里云短信服务三、编写发送短信接...
    99+
    2024-04-02
  • Android开发工程中集成mob短信验证码功能的方法
    一.前言 现在的app基本上都需要用到短信功能,注册时或者有消息通知时需要给用户发送一条短信,但是对于个人开发者来说,去买第三方的短信服务实在是有点奢侈,很好的是mob为我们提...
    99+
    2022-06-06
    方法 工程 验证码 android开发 Android
  • springboot集成teams的方法是什么
    本篇内容主要讲解“springboot集成teams的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springboot集成teams的方法是什么”吧!添加依赖<dependen...
    99+
    2023-06-28
  • Springboot 2.x集成kafka 2.2.0的方法
    本文小编为大家详细介绍“Springboot 2.x集成kafka 2.2.0的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“Springboot 2.x集成kafka 2.2.0的方法”文章能...
    99+
    2023-06-30
  • SpringBoot多数据源集成的方法
    这篇文章主要介绍了SpringBoot多数据源集成的方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot多数据源集成的方法文章都会有所收获,下面我们一起来看看吧。一、多数据源使用场景与弊端1....
    99+
    2023-06-30
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作