1、富文本的使用
2、json类型的字段 可以使用转换成json保存进去
3、省市区三级联动 后端用pid得到list集合,前端发送请求
https://blog.youkuaiyun.com/NaMgAl_/article/details/79018146
依赖、配置文件
config动态配置
启动类加入
@EnableEurekaClient
@EnableConfigServer
<!--
统一配置中心的客户端,注意没有 client
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!--配置文件动态刷新-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
server:
port: 9999 #端口号
spring:
application:
name: travel-config #注册到eureka的服务名
cloud:
config:
server:
git: #访问的地址 仓库地址 +config文件夹+travel-config-name.yml
uri: https://gitee.com/fengyabin/travel-config-2009.git
search-paths: config # 文件夹
#注册中心
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka #eureka服务地址
instance:
prefer-ip-address: true #显示 ip
读取配置文件
server:
port: 7777
spring:
application:
name: travel-system
cloud:
config:
uri: http://localhost:9999 #config服务的端口
profile: datasource,redis,rabbitmq # travel-config-datasource
name: travel-config #config服务的名称
mybatis使用
mybatis:
type-aliases-package: xyz.fuqufyb.aec.entity #所有entity别名类的包
mapper-locations: classpath:mapper/*.xml # mybatis映射文件
configuration:
map-underscore-to-camel-case: true # 开启驼峰式命名
### Ribbon 配置
ribbon:
# 连接超时
ConnectTimeout: 2000
# 响应超时
ReadTimeout: 5000
hystrix:
shareSecurityContext: true
command:
default:
execution:
isolation:
thread:
# 熔断器超时时间,默认:1000/毫秒
timeoutInMilliseconds: 5000
#fastdfs 用于上传图片
fdfs:
connect-timeout: 3000
so-timeout: 3000
thumb-image:
width: 100
height: 100
tracker-list:
- 101.132.226.166:22122
mybatisplus
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
mybatis-plus:
mapper-locations: classpath:mapper/*.xml # mybatis映射文件
configuration:
map-underscore-to-camel-case: true # 开启驼峰式命名
启动类
@MapperScan(“com.springcloud.travel.aviation.dao”) 扫描mapper接口用于代理
Mapper接口继承 extends BaseMapper<Theme>
service接口继承extends IService<Theme>
serviceimpl extends ServiceImpl<ThemeMapper, Theme> implements service
config包
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
PaginationInterceptor page = new PaginationInterceptor();
page.setDialectType("mysql");
return page;
}
}
实现分页
private QueryWrapper getQueryWrapper(Map<String, String> map) {
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
String themeType = (String) map.get("themeType");
// String orderState = (String) map.get("state");
// 判断是否为空
if (!StringUtils.isEmpty(themeType)){
queryWrapper.like("theme_type",themeType);
}
// if (!StringUtils.isEmpty(orderState)){
// queryWrapper.like("order_state",orderState);
// }
return queryWrapper;
}
Page<Theme> pages = new Page<>();
pages.setCurrent(Integer.parseInt(page));
pages.setSize(Integer.parseInt(limit));
//分页查询
Page<Theme> themePage = themeService.page(pages,this.getQueryWrapper(map));
oepnfeign
<!-- openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
#开启feign的降级
feign:
hystrix:
enabled: true
启动类
@EnableFeignClients // 开启 openFeign
必须加参数名@RequestParam(“map”) ,否则无法绑定
//决定调用的服务TRAVEL-THEME
@FeignClient(value = "TRAVEL-THEME",path = "/theme",fallback = ThemeFeignFallBack.class)
public interface ThemeFeign {
/**
* 主题管理的查询
*/
@RequestMapping("/show")
public TableResult<Theme> selectAllTheme(@RequestParam("map") Map<String, String> map);
/**
* 主题管理的增加
*/
@RequestMapping("/add")
public boolean add(@RequestBody Theme theme);
/**
* 主题管理的修改
*/
@RequestMapping("/update")
public boolean update(@RequestBody Theme theme);
/**
* 主题管理的删除
*/
@RequestMapping("/delete")
public boolean delete(@RequestParam("ids") String[] ids);
}
fastdfs
需要加入webuploader包 引入文件
启动类
@Import(FdfsClientConfig.class)//fastdfs
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)//fastdfs
<!--fastdfs用于webupload上传-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.1-RELEASE</version>
</dependency>
thymeleaf 用于读取页面文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
RabbitMQ
<!--用于发送 mq 消息的-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
//input output接口
@EnableBinding({ReceviedAPIRoutingChangeStream.class, LogOutPut.class})
public interface ReceviedAPIRoutingChangeStream {
//交换机名称 用于接收消息
@Input("apiroutingchange")
SubscribableChannel input();
}
//接收消息还需要一个listener 交换机名称 ,能够接收传过来的APIRoutingMQBean
@StreamListener("apiroutingchange")
public void apiMessage(APIRoutingMQBean apiRoutingMQBean){}
public interface LogOutPut {
//交换机名称 发送消息 创建此接口send消息
@Output("logqueue")
MessageChannel out();
//举例
logOutPut.out().send(new GenericMessage<String>(objectMapper.writeValueAsString(loggerBean)));
}
Zuul
@PostConstruct的坑 执行此注解表示这个方法在服务启动时初始化,需要将
断路器 feign ribbon的配置注释掉,否则出现超时异常
启动类
@EnableCircuitBreaker //断路器
@EnableZuulProxy
@PostConstruct
public void init(){
//得到缓存中所有api的key
Set<String> allKeys = cacheFeign.findKeyByPartten("APINAME:*");
System.err.println(allKeys);
if (allKeys!=null&&allKeys.size()>0){
for (String key : allKeys) {
//通过key得到对象
Map<Object, Object> objectObjectMap = cacheFeign.hGetAll(key);
//保存到API_ROUTING_MAP_CACHE中
API_ROUTING_MAP_CACHE.put(key,objectObjectMap);
}
}
System.err.println(API_ROUTING_MAP_CACHE);
}
动态路由
//获取请求路径
RequestContext currentContext = RequestContext.getCurrentContext();
//实现动态路由 根据服务名 路径发送
//服务id openapi-test01 currentContext.put(FilterConstants.SERVICE_ID_KEY,serviceId);
//访问路径 /testservice/test01 currentContext.put(FilterConstants.REQUEST_URI_KEY,insideApiUrl);
事件监听器
@Autowired
private ApplicationContext applicationContext;
//推送事件 事件对象eventBean
applicationContext.publishEvent(eventBean);
//事件监听
@EventListener
public void send(EventBean eventBean) throws GeneralSecurityException, MessagingException {}
spring:
application:
name: openapi-zuul
rabbitmq:
host: 10.36.144.99
username: lee
password: lee
virtual-host: /lee_virtual
eureka:
client:
service-url:
defaultZone: http://localhost:9999/eureka
management:
endpoints:
web:
exposure:
include: "*" #打开所有的监控管理地址
zuul:
routes:
openapi-cache: "/*"
分布式和邮件报警
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--
分布式任务核心依赖
-->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId>
<version>2.1.5</version>
<!--
我们使用的是 ZK 做锁,但是内部的依赖版本在此处不符合我们安装的 zk 版本,我们安装的 ZK 是 3.4.13 版本
-->
<exclusions>
<exclusion>
<artifactId>curator-framework</artifactId>
<groupId>org.apache.curator</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-spring</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--
根据我们的 ZK 版本导入对一个的 curator,因为内置的zookeeper低于我们的 3.4.13 所以我们排除然后导入自己的版本
-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
<exclusions>
<exclusion>
<artifactId>zookeeper</artifactId>
<groupId>org.apache.zookeeper</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
<!--
根据我们的 ZK 版本导入自己的依赖
-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
<!--
邮件报警的依赖
-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>
@Configuration
public class MonitorConfig {
@Value(("${elasticjob.regcenter.serverList}")) String serverList;
@Value(("${elasticjob.regcenter.namespace}")) String nameSpace;
@Value(("${elasticjob.corn}")) String corn;
@Value(("${elasticjob.count}")) int shardingTotalCount;
@Value(("${elasticjob.shardingparamters}")) String shardingparamters;
/**
* 分布式锁注册i中心
*/
@Bean(initMethod = "init")
public ZookeeperRegistryCenter zookeeperRegistryCenter(){
//ZookeeperConfiguration 设置集成和名字
ZookeeperConfiguration zookeeperConfiguration=new ZookeeperConfiguration(serverList,nameSpace);
zookeeperConfiguration.setConnectionTimeoutMilliseconds(10000);
zookeeperConfiguration.setMaxRetries(5);
//直接创建一个ZookeeperRegistryCenter
ZookeeperRegistryCenter zookeeperRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
return zookeeperRegistryCenter;
}
/**
*设置执行周期
*/
@Bean
public LiteJobConfiguration liteJobConfiguration(){
JobCoreConfiguration jobCoreConfiguration= JobCoreConfiguration.newBuilder(MyJob.class.getName(),corn,shardingTotalCount).shardingItemParameters(shardingparamters).build();
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration.newBuilder(new SimpleJobConfiguration(jobCoreConfiguration,MyJob.class.getName())).overwrite(true).build();
return liteJobConfiguration;
}
/**
* 执行任务调度
*/
@Bean(initMethod = "init")
public SpringJobScheduler springJobScheduler(MyJob job,ZookeeperRegistryCenter zookeeperRegistryCenter,LiteJobConfiguration liteJobConfiguration){
return new SpringJobScheduler(job,zookeeperRegistryCenter,liteJobConfiguration);
}
}
执行任务
@Component
public class MyJob implements SimpleJob {
/**
* 任务具体要做的事情
* @param shardingContext
*/
private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Autowired
private SearchFeign searchFeign;
//保存我们的阈值条件 key为apiName value为访问的平均时间
private static Map<String,Integer> mapRule=new HashMap<>();
@Autowired
private ApplicationContext applicationContext;
static {
mapRule.put("oderget_02",30);
mapRule.put("testservice01_03",30);
}
@Override
public void execute(ShardingContext shardingContext) {
System.err.println("开始执行任务");
//因为时区问题 需要减少八个小时 才能和es里面的时间一致
Instant now = Instant.now();
//监听时间段10秒内所有的访问
Date from= Date.from(now.plusSeconds(-3600*8-10));
Date to=Date.from(now.plusSeconds(-3600*8));
// System.out.println(simpleDateFormat.format(from));
// System.out.println(simpleDateFormat.format(to));
//得到保存了apiName 和平均时间的 map
Map<String, Integer> map = searchFeign.getAvg(simpleDateFormat.format(from), simpleDateFormat.format(to));
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
//得到结果的key apiName
String key = entry.getKey();
//得到平均时间 和规则的阈值比较
Integer valueReal = entry.getValue();
Integer valueRule = mapRule.get(key);
if (valueReal<valueRule){
System.err.println("服务" + key + "没有超出阈值");
}
else {
System.err.println("服务" + key + "超出阈值,阈值为" + valueRule + " 当前为:" + valueReal);
EventBean eventBean=new EventBean();
eventBean.setMsg("服务" + key + "超出阈值,阈值为" + valueRule + " 当前为:" + valueReal);
eventBean.setEventType(EventType.OVERTIME);
applicationContext.publishEvent(eventBean);
}
}
//发送邮件
// System.err.println("服务" + "超出阈值,阈值为" + " 当前为:" );
// EventBean eventBean=new EventBean();
// eventBean.setMsg("服务" + "超出阈值,阈值为" + " 当前为:" );
// eventBean.setEventType(EventType.OVERTIME);
// applicationContext.publishEvent(eventBean);
}
}
事件监听 发送邮件报警
@Component
public class SendMailEventListener {
@EventListener
public void send(EventBean eventBean) throws GeneralSecurityException, MessagingException {
switch (eventBean.getEventType()) {
case OVERTIME:
Properties properties = new Properties();
properties.put("mail.host", "smtp.163.com");//设置我们的服务器地址
properties.put("mail.transport.protocol", "smtp");//设置邮箱发送的协议
properties.put("mail.smtp.auth", "true");//设置需要认证
MailSSLSocketFactory sf = new MailSSLSocketFactory();//创建 ssl 连接的工厂对象
sf.setTrustAllHosts(true);//信任所有主机
properties.put("mail.smtp.ssl.enable", "true");//设置开启 ssl
properties.put("mail.smtp.ssl.socketFactory", sf);//设置对应的工厂对象
Session session = Session.getDefaultInstance(properties, new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("chenzetao88886@163.com", "NGCTKBVTVUTDMDUF"); //返回认证信息
}
});//创建会话
session.setDebug(true);//控制台会显示一些调试的日志
Transport transport = session.getTransport();//类似于我们的 sql 中的 statement
transport.connect("smtp.163.com", "chenzetao88886@163.com", "NGCTKBVTVUTDMDUF");//通过邮箱和提供的密码来进行登录
Message message = new MimeMessage(session);//创建消息对象,也就是邮件内容对象
message.setFrom(new InternetAddress("chenzetao88886@163.com"));//设置对方显示的来自于谁的邮件
//设置收件人
message.setRecipients(Message.RecipientType.TO, new InternetAddress[]{new InternetAddress("852086428@qq.com")});//设置收件人
message.setSubject("接口超时预警邮件");//标题
message.setContent(eventBean.getMsg(), "text/html;charset=utf-8");//正文
transport.sendMessage(message, message.getAllRecipients());//发送
transport.close();
break;
}
}}
其他依赖
<dependencies>
<dependency>
<groupId>com.spingcloud</groupId>
<artifactId>travel-entity</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 实体类-->
<dependency>
<groupId>com.spingcloud</groupId>
<artifactId>travel-entity</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 过滤掉掉 mybatis-plus 依赖,之前用的是mybatis-->
<exclusions>
<exclusion>
<artifactId>mybatis-plus-boot-starter</artifactId>
<groupId>com.baomidou</groupId>
</exclusion>
</exclusions>
</dependencies>
依赖
<!--pagehelper注意和mybatisplus的问题-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!--注册到eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependency>
<!-- hystrix 断路器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- jwt 认证用于sign签名 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!--es-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.4</version>
<!--<exclusions>-->
<!--<exclusion>-->
<!--<artifactId>elasticsearch</artifactId>-->
<!--<groupId>org.elasticsearch</groupId>-->
<!--</exclusion>-->
<!--</exclusions>-->
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.5.4</version>
</dependency>
<!--eureka服务端 启动类@EnableEurekaServer注解-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
.gitignore的忽略文件配置
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/