feat:添加邮箱消息通知

V0.5.x
荭琪枫 2023-05-11 23:01:08 +08:00
parent 153d271414
commit a53bc698ee
23 changed files with 550 additions and 38 deletions

23
data/init/channel.json Normal file
View File

@ -0,0 +1,23 @@
[
{
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb831",
"code": "DingTalk",
"title": "钉钉",
"icon": "http://www.baidu.com",
"createAt": 1683816661690
},
{
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb832",
"code": "QyWechat",
"title": "企业微信",
"icon": "http://www.baidu.com",
"createAt": 1683816661690
},
{
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb833",
"code": "Email",
"title": "邮箱",
"icon": "http://www.baidu.com",
"createAt": 1683816661690
}
]

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>iot-components</artifactId>
<groupId>cc.iotkit</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>iot-component-swagger</artifactId>
<dependencies>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--springfox swagger官方Starter-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
此模块为通用业务逻辑或工具类

View File

@ -0,0 +1,20 @@
package cc.iotkit.swagger.annotation;
import cc.iotkit.swagger.config.SwaggerProperties;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
/**
* @Author:
* @Date: 2023/5/6 22:12
* @Description:
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(SwaggerProperties.class)
public @interface EnableIotKitSwagger2 {
}

View File

@ -0,0 +1,120 @@
package cc.iotkit.swagger.config;
import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.*;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* @Author:
* @Date: 2023/5/6 22:03
* @Description:
*/
@Configuration
@EnableSwagger2
@EnableAutoConfiguration
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@EnableKnife4j
public class SwaggerAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public SwaggerProperties swaggerProperties() {
return new SwaggerProperties();
}
@Bean
public List<Docket> createRestApi(SwaggerProperties swaggerProperties) {
List<Docket> docketList = new LinkedList<>();
if (swaggerProperties.getDocket().isEmpty()) {
ApiSelectorBuilder docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo(swaggerProperties))
.enable(swaggerProperties.getEnabled())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class));
if (StringUtils.isNotBlank(swaggerProperties.getBasePackage())) {
docket.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
}
swaggerProperties.getBasePath().forEach(p -> docket.paths(PathSelectors.ant(p)));
swaggerProperties.getExcludePath().forEach(p -> docket.paths(PathSelectors.ant(p).negate()));
docketList.add(
docket.build()
.globalRequestParameters(getGlobalRequestParameters())
.globalResponses(HttpMethod.GET, getGlobalResponseMessage())
.globalResponses(HttpMethod.POST, getGlobalResponseMessage()));
}
swaggerProperties.getDocket().forEach((k, v) -> {
SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(k);
ApiInfo apiInfo = new ApiInfoBuilder()
//页面标题
.title(docketInfo.getTitle())
//创建人
.contact(new Contact(docketInfo.getContact().getName(),
docketInfo.getContact().getUrl(),
docketInfo.getContact().getEmail()))
.version(docketInfo.getVersion())
.description(docketInfo.getDescription())
.build();
ApiSelectorBuilder docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.enable(swaggerProperties.getEnabled())
.groupName(docketInfo.getGroup())
.select()
//为当前包路径
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class));
if (StringUtils.isNotBlank(docketInfo.getBasePackage())) {
docket.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
}
swaggerProperties.getBasePath().forEach(p -> docket.paths(PathSelectors.ant(p)));
swaggerProperties.getExcludePath().forEach(p -> docket.paths(PathSelectors.ant(p).negate()));
docketList.add(docket.build());
});
return docketList;
}
@Bean
public ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.version(swaggerProperties.getVersion())
.description(swaggerProperties.getDescription())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.build();
}
/**
* head
*/
private List<RequestParameter> getGlobalRequestParameters() {
List<RequestParameter> parameters = new ArrayList<>();
parameters.add(new RequestParameterBuilder()
.name("token")
.description("令牌")
.required(false)
.in(ParameterType.HEADER)
.build());
return parameters;
}
private List<Response> getGlobalResponseMessage() {
List<Response> responseList = new ArrayList<>();
responseList.add(new ResponseBuilder().code("404").description("找不到资源").build());
return responseList;
}
}

View File

@ -0,0 +1,60 @@
package cc.iotkit.swagger.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @Author:
* @Date: 2023/5/6 22:26
* @Description:
*/
@Data
@Component
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {
private Boolean enabled;
private String title; //标题
private String group; //自定义组名
private String description = "在线文档"; //描述
private String version = "1.0"; //版本
private Contact contact = new Contact(); //联系人
private String basePackage = "com.example"; //swagger会解析的包路径
private List<String> basePath = new ArrayList<>(); //swagger会解析的url规则
private List<String> excludePath = new ArrayList<>();//在basePath基础上需要排除的url规则
private Map<String, DocketInfo> docket = new LinkedHashMap<>(); //分组文档
public String getGroup() {
if (group == null || "".equals(group)) {
return title;
}
return group;
}
@Data
public static class DocketInfo {
private String title = "在线文档"; //标题
private String group = ""; //自定义组名
private String description = "在线文档"; //描述
private String version = "1.0"; //版本
private Contact contact = new Contact(); //联系人
private String basePackage = "com.example"; //swagger会解析的包路径
private List<String> basePath = new ArrayList<>(); //swagger会解析的url规则
private List<String> excludePath = new ArrayList<>();//在basePath基础上需要排除的url
public String getGroup() {
if (group == null || "".equals(group)) {
return title;
}
return group;
}
}
@Data
public static class Contact {
private String name = ""; //联系人
private String url = ""; //联系人url
private String email = ""; //联系人email
}
}

View File

@ -0,0 +1,20 @@
package cc.iotkit.swagger.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author:
* @Date: 2023/5/6 22:03
* @Description:
*/
@Configuration
public class SwaggerWebConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html", "doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}

View File

@ -0,0 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cc.iotkit.swagger.config.SwaggerWebConfiguration,\
cc.iotkit.swagger.config.SwaggerWebConfiguration

View File

@ -14,6 +14,7 @@
<modules>
<module>iot-component-server</module>
<module>iot-component-converter</module>
<module>iot-component-swagger</module>
<module>iot-mqtt-component</module>
<module>iot-emqx-component</module>
<module>iot-component-base</module>

View File

@ -1,6 +1,5 @@
package cc.iotkit.data;
import cc.iotkit.model.notify.Channel;
import cc.iotkit.model.notify.ChannelConfig;
/**

View File

@ -26,4 +26,5 @@ public class Channel implements Id<String> {
private String icon;
private Long createAt;
}

View File

@ -1,7 +1,6 @@
package cc.iotkit.model.notify;
import cc.iotkit.model.Id;
import cc.iotkit.model.Owned;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

View File

@ -1,7 +1,6 @@
package cc.iotkit.model.notify;
import cc.iotkit.model.Id;
import cc.iotkit.model.Owned;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -19,4 +18,12 @@ import lombok.NoArgsConstructor;
public class ChannelTemplate implements Id<String> {
private String id;
private String channelConfigId;
private String title;
private String content;
private Long createAt;
}

View File

@ -0,0 +1,12 @@
package cc.iotkit.data.dao;
import cc.iotkit.data.model.TbChannelConfig;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author:
* @Date: 2023/5/11 21:00
* @Description:
*/
public interface ChannelConfigRepository extends JpaRepository<TbChannelConfig, String> {
}

View File

@ -0,0 +1,12 @@
package cc.iotkit.data.dao;
import cc.iotkit.data.model.TbChannelTemplate;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @Author:
* @Date: 2023/5/11 21:00
* @Description:
*/
public interface ChannelTemplateRepository extends JpaRepository<TbChannelTemplate, String> {
}

View File

@ -0,0 +1,19 @@
package cc.iotkit.data.model;
import cc.iotkit.model.notify.ChannelConfig;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @Author:
* @Date: 2023/5/11 21:02
* @Description:
*/
@Mapper
public interface ChannelConfigMapper {
ChannelConfigMapper M = Mappers.getMapper(ChannelConfigMapper.class);
ChannelConfig toDto(TbChannelConfig vo);
TbChannelConfig toVo(ChannelConfig dto);
}

View File

@ -0,0 +1,19 @@
package cc.iotkit.data.model;
import cc.iotkit.model.notify.ChannelTemplate;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @Author:
* @Date: 2023/5/11 21:02
* @Description:
*/
@Mapper
public interface ChannelTemplateMapper {
ChannelTemplateMapper M = Mappers.getMapper(ChannelTemplateMapper.class);
ChannelTemplate toDto(TbChannelTemplate vo);
TbChannelTemplate toVo(ChannelTemplate dto);
}

View File

@ -0,0 +1,28 @@
package cc.iotkit.data.model;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @Author:
* @Date: 2023/5/11 20:58
* @Description:
*/
@Data
@Entity
@Table(name = "channel_config")
public class TbChannelConfig {
@Id
private String id;
private String channelId;
private String title;
private String param;
private Long createAt;
}

View File

@ -0,0 +1,28 @@
package cc.iotkit.data.model;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* @Author:
* @Date: 2023/5/11 20:59
* @Description:
*/
@Data
@Entity
@Table(name = "channel_template")
public class TbChannelTemplate {
@Id
private String id;
private String channelConfigId;
private String title;
private String content;
private Long createAt;
}

View File

@ -1,12 +1,21 @@
package cc.iotkit.data.service;
import cc.iotkit.data.IChannelConfigData;
import cc.iotkit.data.dao.ChannelConfigRepository;
import cc.iotkit.data.model.ChannelConfigMapper;
import cc.iotkit.data.model.TbChannelConfig;
import cc.iotkit.model.Paging;
import cc.iotkit.model.notify.ChannelConfig;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* author:
@ -17,38 +26,53 @@ import java.util.List;
@Service
public class ChannelConfigDataImpl implements IChannelConfigData {
@Resource
private ChannelConfigRepository channelConfigRepository;
@Override
public ChannelConfig findById(String s) {
return null;
public ChannelConfig findById(String id) {
return ChannelConfigMapper.M.toDto(channelConfigRepository.findById(id).orElse(null));
}
@Override
public ChannelConfig save(ChannelConfig data) {
return null;
if (StringUtils.isBlank(data.getId())) {
data.setId(UUID.randomUUID().toString());
}
channelConfigRepository.save(ChannelConfigMapper.M.toVo(data));
return data;
}
@Override
public ChannelConfig add(ChannelConfig data) {
return null;
data.setCreateAt(System.currentTimeMillis());
return save(data);
}
@Override
public void deleteById(String s) {
public void deleteById(String id) {
channelConfigRepository.deleteById(id);
}
@Override
public long count() {
return 0;
return channelConfigRepository.count();
}
@Override
public List<ChannelConfig> findAll() {
return null;
return channelConfigRepository.findAll().stream().map(ChannelConfigMapper.M::toDto)
.collect(Collectors.toList());
}
@Override
public Paging<ChannelConfig> findAll(int page, int size) {
return null;
Page<TbChannelConfig> tbDeviceConfigs = channelConfigRepository.findAll(Pageable.ofSize(size).withPage(page - 1));
return new Paging<>(
tbDeviceConfigs.getTotalElements(),
tbDeviceConfigs.getContent()
.stream().map(ChannelConfigMapper.M::toDto)
.collect(Collectors.toList())
);
}
}

View File

@ -6,6 +6,7 @@ import cc.iotkit.data.model.ChannelMapper;
import cc.iotkit.data.model.TbChannel;
import cc.iotkit.model.Paging;
import cc.iotkit.model.notify.Channel;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@ -13,6 +14,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
@ -28,33 +30,39 @@ public class ChannelDataImpl implements IChannelData {
private ChannelRepository channelRepository;
@Override
public Channel findById(String s) {
return null;
public Channel findById(String id) {
return ChannelMapper.M.toDto(channelRepository.findById(id).orElse(null));
}
@Override
public Channel save(Channel data) {
return null;
if (StringUtils.isBlank(data.getId())) {
data.setId(UUID.randomUUID().toString());
}
channelRepository.save(ChannelMapper.M.toVo(data));
return data;
}
@Override
public Channel add(Channel data) {
return null;
data.setCreateAt(System.currentTimeMillis());
return save(data);
}
@Override
public void deleteById(String s) {
public void deleteById(String id) {
channelRepository.deleteById(id);
}
@Override
public long count() {
return 0;
return channelRepository.count();
}
@Override
public List<Channel> findAll() {
return null;
return channelRepository.findAll().stream().map(ChannelMapper.M::toDto)
.collect(Collectors.toList());
}
@Override

View File

@ -1,12 +1,21 @@
package cc.iotkit.data.service;
import cc.iotkit.data.IChannelTemplateData;
import cc.iotkit.data.dao.ChannelTemplateRepository;
import cc.iotkit.data.model.ChannelTemplateMapper;
import cc.iotkit.data.model.TbChannelTemplate;
import cc.iotkit.model.Paging;
import cc.iotkit.model.notify.ChannelTemplate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* author:
@ -16,38 +25,54 @@ import java.util.List;
@Primary
@Service
public class ChannelTemplateDataImpl implements IChannelTemplateData {
@Resource
private ChannelTemplateRepository channelTemplateRepository;
@Override
public ChannelTemplate findById(String s) {
return null;
public ChannelTemplate findById(String id) {
return ChannelTemplateMapper.M.toDto(channelTemplateRepository.findById(id).orElse(null));
}
@Override
public ChannelTemplate save(ChannelTemplate data) {
return null;
if (StringUtils.isBlank(data.getId())) {
data.setId(UUID.randomUUID().toString());
}
channelTemplateRepository.save(ChannelTemplateMapper.M.toVo(data));
return data;
}
@Override
public ChannelTemplate add(ChannelTemplate data) {
return null;
data.setCreateAt(System.currentTimeMillis());
return save(data);
}
@Override
public void deleteById(String s) {
public void deleteById(String id) {
channelTemplateRepository.deleteById(id);
}
@Override
public long count() {
return 0;
return channelTemplateRepository.count();
}
@Override
public List<ChannelTemplate> findAll() {
return null;
return channelTemplateRepository.findAll().stream().map(ChannelTemplateMapper.M::toDto)
.collect(Collectors.toList());
}
@Override
public Paging<ChannelTemplate> findAll(int page, int size) {
return null;
Page<TbChannelTemplate> tbDeviceConfigs = channelTemplateRepository.findAll(Pageable.ofSize(size).withPage(page - 1));
return new Paging<>(
tbDeviceConfigs.getTotalElements(),
tbDeviceConfigs.getContent()
.stream().map(ChannelTemplateMapper.M::toDto)
.collect(Collectors.toList())
);
}
}

View File

@ -1,8 +1,17 @@
package cc.iotkit.manager.service;
import cc.iotkit.data.IChannelConfigData;
import cc.iotkit.data.IChannelData;
import cc.iotkit.data.IChannelTemplateData;
import cc.iotkit.model.notify.Channel;
import cc.iotkit.model.notify.ChannelConfig;
import cc.iotkit.model.notify.ChannelTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* author:
* date: 2023-05-11 15:21
@ -12,37 +21,58 @@ import org.springframework.stereotype.Service;
@Service
public class NotifyService {
public void getChannelList() {
@Resource
private IChannelData iChannelData;
@Resource
private IChannelConfigData iChannelConfigData;
@Resource
private IChannelTemplateData iChannelTemplateData;
public List<Channel> getChannelList() {
return iChannelData.findAll();
}
public void getChannelConfigList() {
public List<ChannelConfig> getChannelConfigList() {
return iChannelConfigData.findAll();
}
public void addChannelConfig() {
ChannelConfig channelConfig = ChannelConfig.builder()
.build();
iChannelConfigData.add(channelConfig);
}
public void getChannelConfigById() {
public ChannelConfig getChannelConfigById(String id) {
return iChannelConfigData.findById(id);
}
public void updateChannelConfigById() {
public ChannelConfig updateChannelConfigById(ChannelConfig channelConfig) {
return iChannelConfigData.save(channelConfig);
}
public void delChannelConfigById() {
public void delChannelConfigById(String id) {
iChannelConfigData.deleteById(id);
}
public void getChannelTemplateList() {
}
public void addChannelTemplate() {
}
public void getChannelTemplateById() {
public ChannelTemplate getChannelTemplateById(String id) {
return iChannelTemplateData.findById(id);
}
public void updateChannelTemplateById() {
public void updateChannelTemplateById(ChannelTemplate channelTemplate) {
iChannelTemplateData.save(channelTemplate);
}
public void delChannelTemplateById() {
public void delChannelTemplateById(String id) {
iChannelTemplateData.deleteById(id);
}
}