Commit 6666f7d8 authored by lihaipeng's avatar lihaipeng

增加Redis、日志处理等

parent 14ef305f
...@@ -61,6 +61,12 @@ ...@@ -61,6 +61,12 @@
</dependencyManagement> </dependencyManagement>
<build> <build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
......
package com.unififi.demo.service; package com.unififi.api;
import com.unififi.demo.model.User; import com.unififi.model.User;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@FeignClient(value = "unififi-demo2-service") @FeignClient(value = "unififi-demo2-service")
public interface UserService { public interface UserApi {
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
String echo(@PathVariable String string); String echo(@PathVariable String string);
...@@ -18,7 +19,7 @@ public interface UserService { ...@@ -18,7 +19,7 @@ public interface UserService {
@GetMapping("/user/get") @GetMapping("/user/get")
User get(@RequestParam("name") String name); User get(@RequestParam("name") String name);
@PostMapping("/user/add") @PostMapping(value = "/user/add", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
Boolean add(@RequestBody User user); Boolean add(@RequestBody User user);
} }
package com.unififi.demo.model; package com.unififi.model;
import lombok.Data; import lombok.Data;
......
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>unififi-spring-cloud-guide</artifactId> <artifactId>unififi-spring-cloud-guide</artifactId>
<groupId>com.unififi</groupId> <groupId>com.unififi</groupId>
<version>0.0.1</version> <version>0.0.1</version>
</parent> </parent>
<artifactId>unififi-demo1-service</artifactId> <artifactId>unififi-demo1-service</artifactId>
<version>${unififi-service.version}</version> <version>${unififi-service.version}</version>
...@@ -27,6 +26,11 @@ ...@@ -27,6 +26,11 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
...@@ -39,18 +43,76 @@ ...@@ -39,18 +43,76 @@
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency> </dependency>
<!-- OpenFeign配置 -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.alibaba.cloud</groupId> <groupId>io.github.openfeign</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <artifactId>feign-httpclient</artifactId>
<version>10.7.4</version>
</dependency>
<!-- 重试模块 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<!-- 数据库相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency> </dependency>
<!-- <dependency>--> <dependency>
<!-- <groupId>org.springframework.retry</groupId>--> <groupId>mysql</groupId>
<!-- <artifactId>spring-retry</artifactId>--> <artifactId>mysql-connector-java</artifactId>
<!-- </dependency>--> <version>5.1.49</version>
</dependency>
<!-- mybatis代码生成 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<!-- redis配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- 动态配置监听 -->
<dependency>
<groupId>com.purgeteam</groupId>
<artifactId>dynamic-config-spring-boot-starter</artifactId>
<version>0.1.0.RELEASE</version>
</dependency>
<!-- 测试相关 -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
...@@ -63,5 +125,4 @@ ...@@ -63,5 +125,4 @@
</exclusions> </exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
package com.unififi.demo; package com.unififi;
import com.purgeteam.dynamic.config.starter.annotation.EnableDynamicConfigEvent;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication @SpringBootApplication
@EnableDiscoveryClient @EnableDiscoveryClient
@EnableFeignClients @EnableFeignClients
@EnableDynamicConfigEvent
public class Demo1Application { public class Demo1Application {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args); SpringApplication.run(Demo1Application.class, args);
} }
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public RestTemplate restTemplate1() {
return new RestTemplate();
}
} }
package com.unififi.demo.config; package com.unififi.config;
import lombok.Getter; import lombok.Getter;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
...@@ -11,5 +11,5 @@ import org.springframework.context.annotation.Configuration; ...@@ -11,5 +11,5 @@ import org.springframework.context.annotation.Configuration;
public class AppConfig { public class AppConfig {
@Value("${user.name}") @Value("${user.name}")
public String username; private String username;
} }
package com.unififi.config;
import com.purgeteam.dynamic.config.starter.event.ActionConfigEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AppConfigListener implements ApplicationListener<ActionConfigEvent> {
@Override
public void onApplicationEvent(ActionConfigEvent event) {
log.info("配置变更");
log.info(event.getPropertyMap().toString());
}
}
\ No newline at end of file
package com.unififi.config.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* 统一异常处理
*/
@Slf4j
@RestControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class)
public Map handleException(Exception e) {
Map map = new HashMap();
map.put("code", 500);
map.put("msg", "系统错误");
log.error("Exception: ", e);
return map;
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Map handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
Map map = new HashMap();
map.put("code", 501);
map.put("msg", "方法不支持");
log.error("HttpRequestMethodNotSupportedException: ", e);
return map;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
Map map = new HashMap();
map.put("code", 502);
map.put("msg", "参数错误");
log.error("MethodArgumentNotValidException: ", e);
return map;
}
}
package com.unififi.config.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.unififi.config.logger.LoggerConfig;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
public class ControllerLogAspect {
private final static Logger logger = LoggerFactory.getLogger("ControllerAspectLog");
@Autowired
private LoggerConfig loggerConfig;
@Pointcut("execution(* com.unififi.controller.*.*(..))")
public void printLog() {
}
@Around("printLog()")
private Object doAround(ProceedingJoinPoint pjp) {
try {
long start = System.nanoTime();
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
String requestData = null;
if ("POST".equalsIgnoreCase(request.getMethod()) || "PUT".equalsIgnoreCase(request.getMethod())) {
requestData = JSONArray.toJSONString(pjp.getArgs());
} else if ("GET".equalsIgnoreCase(request.getMethod())) {
requestData = request.getQueryString();
}
if (logger.isInfoEnabled() && loggerConfig.getController().isEnabled()) {
if (!loggerConfig.getController().getSkipMethodSigns().contains(pjp.getSignature().toShortString())) {
logger.info("Unififi-REQ-[{}] {}", pjp.getSignature().toShortString(), (requestData != null ? requestData : ""));
}
}
Object result = pjp.proceed();
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
String responseData = null;
if (result != null) {
responseData = JSON.toJSONString(result);
}
if (logger.isInfoEnabled() && loggerConfig.getController().isEnabled()) {
if (!loggerConfig.getController().getSkipMethodSigns().contains(pjp.getSignature().toShortString())) {
if (loggerConfig.getController().getIgnoreResponseDataMethodSigns().contains(pjp.getSignature().toShortString())) {
logger.info("Unififi-RESP-[{}] IGNORE_DATA size:{} spend:{}ms", pjp.getSignature().toShortString(), (responseData != null ? responseData.length() : 0), elapsedTime);
} else {
logger.info("Unififi-RESP-[{}] {} size:{} spend:{}ms", pjp.getSignature().toShortString(), (responseData != null ? responseData : ""), (responseData != null ? responseData.length() : 0), elapsedTime);
}
}
}
return result;
} catch (Throwable throwable) {
if (logger.isErrorEnabled() && loggerConfig.getController().isEnabled()) {
logger.error("Unififi-RESP-[{}] {}: {}", pjp.getSignature().toShortString(), throwable.getClass().getSimpleName(), throwable.getMessage());
}
return throwable;
}
}
}
package com.unififi.config.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class HttpMessageConverterConfig {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializerFeature[] serializerFeatures = new SerializerFeature[]{
// Date的日期转换器
SerializerFeature.WriteDateUseDateFormat,
// 循环引用
SerializerFeature.DisableCircularReferenceDetect
};
fastJsonConfig.setSerializerFeatures(serializerFeatures);
fastJsonConfig.setCharset(Charset.forName("UTF-8"));
fastConverter.setFastJsonConfig(fastJsonConfig);
List<MediaType> fastjsonSupportedMediaTypes = new ArrayList<>();
fastjsonSupportedMediaTypes.add(MediaType.TEXT_PLAIN);
fastjsonSupportedMediaTypes.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(fastjsonSupportedMediaTypes);
return new HttpMessageConverters(fastConverter);
}
private static class UnififiFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
private static final Logger logger = LoggerFactory.getLogger("ControllerLog");
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException {
Object obj = super.read(type, contextClass, inputMessage);
if (logger.isInfoEnabled()) {
logger.info("Unififi-REQ-[{}] {}", type.getTypeName(), JSON.toJSONString(obj));
}
return obj;
}
@Override
public void write(Object t, Type type, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (type.getTypeName().endsWith("ListResp")) {
if (logger.isInfoEnabled()) {
logger.info("Unififi-RESP-[{}] {}", type.getTypeName(), "LIST_IGNORE");
}
} else {
if (logger.isInfoEnabled()) {
logger.info("Unififi-RESP-[{}] {}", type.getTypeName(), JSON.toJSONString(t));
}
}
super.write(t, type, contentType, outputMessage);
}
}
}
package com.unififi.config.feign;
import com.unififi.config.logger.LoggerConfig;
import feign.Logger;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.FeignLoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
@ConditionalOnMissingBean(LoggerConfig.class)
LoggerConfig loggerConfig() {
return new LoggerConfig();
}
@Bean
Logger.Level feignLevel() {
return Logger.Level.NONE;
}
@Bean
FeignLoggerFactory infoFeignLoggerFactory(LoggerConfig loggerConfig) {
return new UnififiFeignLoggerFactory(loggerConfig.getFeign());
}
}
package com.unififi.config.feign;
import com.unififi.config.logger.LoggerConfig;
import feign.Request;
import feign.Response;
import feign.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.Charset;
import static feign.Util.decodeOrDefault;
public class UnififiFeignLogger extends feign.Logger {
private static final Logger logger = LoggerFactory.getLogger("FeignLog");
public static final Charset UTF_8 = Charset.forName("UTF-8");
// private final Logger logger;
private LoggerConfig.Setting setting;
public UnififiFeignLogger(Logger logger, LoggerConfig.Setting setting) {
// this.logger = logger;
this.setting = setting;
}
@Override
protected void logRequest(String configKey, Level logLevel, Request request) {
if (logger.isInfoEnabled() && setting.isEnabled()) {
if (!setting.getSkipMethodSigns().contains(configKey)) {
logger.info("FEIGN-REQ-[{}] {} --> {} {}", configKey, request.body() != null ? new String(request.body(), UTF_8) : "", request.httpMethod(), request.url());
}
}
}
@Override
protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
if (response.body() != null) {
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
if (logger.isInfoEnabled() && setting.isEnabled()) {
if (!setting.getSkipMethodSigns().contains(configKey)) {
if (setting.getIgnoreResponseDataMethodSigns().contains(configKey)) {
logger.info("FEIGN-RESP-[{}] IGNORE_DATA size:{} spend:{}ms", configKey, (bodyData != null ? bodyData.length : 0), elapsedTime);
} else {
logger.info("FEIGN-RESP-[{}] {} size:{} spend:{}ms", configKey, decodeOrDefault(bodyData, UTF_8, ""), (bodyData != null ? bodyData.length : 0), elapsedTime);
}
}
}
return response.toBuilder().body(bodyData).build();
} else {
if (logger.isInfoEnabled() && setting.isEnabled()) {
if (!setting.getSkipMethodSigns().contains(configKey)) {
logger.info("FEIGN-RESP-[{}] size:0 spend:{}ms", configKey, elapsedTime);
}
}
return response;
}
}
@Override
protected IOException logIOException(String configKey, Level logLevel, IOException ioe, long elapsedTime) {
if (logger.isErrorEnabled() && setting.isEnabled()) {
logger.error("FEIGN-RESP-[{}] {}: {}", configKey, ioe.getClass().getSimpleName(), ioe.getMessage());
}
return ioe;
}
@Override
protected void log(String configKey, String format, Object... args) {
if (logger.isInfoEnabled()) {
logger.info(String.format(methodTag(configKey) + format, args));
}
}
}
package com.unififi.config.feign;
import com.unififi.config.logger.LoggerConfig;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FeignLoggerFactory;
public class UnififiFeignLoggerFactory implements FeignLoggerFactory {
private LoggerConfig.Setting setting;
public UnififiFeignLoggerFactory(LoggerConfig.Setting setting) {
this.setting = setting;
}
@Override
public feign.Logger create(Class<?> type) {
return new UnififiFeignLogger(LoggerFactory.getLogger(type), this.setting);
}
}
package com.unififi.config.logger;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(ignoreInvalidFields = true, prefix = LoggerConfig.PREFIX)
public class LoggerConfig {
public static final String PREFIX = "unififi.logger";
private Setting feign = new Setting();
private Setting rest = new Setting();
private Setting controller = new Setting();
public Setting getFeign() {
return feign;
}
public void setFeign(Setting feign) {
this.feign = feign;
}
public Setting getRest() {
return rest;
}
public void setRest(Setting rest) {
this.rest = rest;
}
public Setting getController() {
return controller;
}
public void setController(Setting controller) {
this.controller = controller;
}
public static class Setting {
private boolean enabled = true;
private List<String> ignoreResponseDataMethodSigns = new ArrayList<>();
private List<String> skipMethodSigns = new ArrayList<>();
private boolean showSpendms = false;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public List<String> getIgnoreResponseDataMethodSigns() {
return ignoreResponseDataMethodSigns;
}
public void setIgnoreResponseDataMethodSigns(List<String> ignoreResponseDataMethodSigns) {
this.ignoreResponseDataMethodSigns = ignoreResponseDataMethodSigns;
}
public List<String> getSkipMethodSigns() {
return skipMethodSigns;
}
public void setSkipMethodSigns(List<String> skipMethodSigns) {
this.skipMethodSigns = skipMethodSigns;
}
public boolean isShowSpendms() {
return showSpendms;
}
public void setShowSpendms(boolean showSpendms) {
this.showSpendms = showSpendms;
}
}
}
package com.unififi.demo.config; package com.unififi.config.mybatis;
import com.baomidou.mybatisplus.core.parser.ISqlParser; import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser; import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;
...@@ -14,7 +14,7 @@ import java.util.List; ...@@ -14,7 +14,7 @@ import java.util.List;
@EnableTransactionManagement @EnableTransactionManagement
@Configuration @Configuration
@MapperScan(basePackages = {"com.unififi.*.mapper*"}) @MapperScan(basePackages = {"com.unififi.mapper"})
public class MybatisPlusConfig { public class MybatisPlusConfig {
@Bean @Bean
......
package com.unififi.config.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// key采用String的序列化方式
template.setKeySerializer(RedisSerializer.string());
// hash的key也采用String的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
\ No newline at end of file
package com.unififi.config.rest;
import com.unififi.config.logger.LoggerConfig;
import org.apache.http.client.HttpClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@ConditionalOnMissingBean(LoggerConfig.class)
LoggerConfig loggerConfig() {
return new LoggerConfig();
}
@Bean
public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
httpComponentsClientHttpRequestFactory.setConnectTimeout(5000);
httpComponentsClientHttpRequestFactory.setReadTimeout(60000);
return httpComponentsClientHttpRequestFactory;
}
@LoadBalanced
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory httpRequestFactory, LoggerConfig loggerConfig) {
BufferingClientHttpRequestFactory bufferingClientHttpRequestFactory = new BufferingClientHttpRequestFactory(httpRequestFactory);
RestTemplate restTemplate = new RestTemplate(bufferingClientHttpRequestFactory);
restTemplate.getInterceptors().add(new RestTemplateLogInterceptor(loggerConfig.getRest()));
return restTemplate;
}
}
package com.unififi.config.rest;
import com.unififi.config.logger.LoggerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
public class RestTemplateLogInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger("RestTemplateLog");
public static final Charset UTF_8 = Charset.forName("UTF-8");
private LoggerConfig.Setting setting;
public RestTemplateLogInterceptor(LoggerConfig.Setting setting) {
this.setting = setting;
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
String methodTag = getMethodTag(request.getURI());
if (logger.isInfoEnabled() && setting.isEnabled()) {
if (!setting.getSkipMethodSigns().contains(methodTag)) {
logger.info("REST-REQ-[{}] {} --> {} {}", methodTag, body != null ? new String(body, UTF_8) : "", request.getMethod(), request.getURI());
}
}
long start = System.nanoTime();
ClientHttpResponse response = null;
try {
response = execution.execute(request, body);
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (logger.isInfoEnabled()) {
StringBuilder inputStringBuilder = new StringBuilder();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), UTF_8))) {
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
line = bufferedReader.readLine();
if (line != null) {
inputStringBuilder.append('\n');
}
}
}
if (logger.isInfoEnabled() && setting.isEnabled()) {
if (!setting.getSkipMethodSigns().contains(methodTag)) {
if (setting.getIgnoreResponseDataMethodSigns().contains(methodTag)) {
logger.info("REST-RESP-[{}] IGNORE_DATA size:{} spend:{}ms", methodTag, inputStringBuilder.length(), elapsedTime);
} else {
logger.info("REST-RESP-[{}] {} size:{} spend:{}ms", methodTag, inputStringBuilder.toString(), inputStringBuilder.length(), elapsedTime);
}
}
}
}
} catch (IOException ioe) {
if (logger.isErrorEnabled() && setting.isEnabled()) {
logger.error("REST-RESP-[{}] {}: {}", methodTag, ioe.getClass().getSimpleName(), ioe.getMessage());
}
throw ioe;
}
return response;
}
private String getMethodTag(URI uri) {
try {
if (uri.getPath().indexOf('?') > -1) {
return uri.getHost() + uri.getPath().substring(0, uri.getPath().indexOf('?'));
} else {
return uri.getHost() + uri.getPath();
}
} catch (Exception e) {
return uri.getHost() + uri.getPath();
}
}
}
package com.unififi.config.ribbon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.listener.RetryListenerSupport;
public class RetryLogListener extends RetryListenerSupport {
private static final Logger logger = LoggerFactory.getLogger("RibbonRetryLog");
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
logger.warn("UNIFIFI-RETRY serviceId:{} count:{} exhausted:{} msg:{}", ((LoadBalancedRetryContext) context).getServiceInstance().getServiceId(), context.getRetryCount(), context.isExhaustedOnly(), throwable.getMessage());
}
}
package com.unififi.config.ribbon;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RibbonConfig {
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(
final SpringClientFactory clientFactory) {
return new UnififiRibbonLoadBalancedRetryFactory(clientFactory);
}
}
package com.unififi.config.ribbon;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.retry.RetryListener;
public class UnififiRibbonLoadBalancedRetryFactory extends RibbonLoadBalancedRetryFactory {
private RetryListener[] retryListener = {new RetryLogListener()};
public UnififiRibbonLoadBalancedRetryFactory(SpringClientFactory clientFactory) {
super(clientFactory);
}
@Override
public RetryListener[] createRetryListeners(String service) {
return retryListener;
}
}
package com.unififi.demo.controller; package com.unififi.controller;
import com.unififi.demo.config.AppConfig; import com.unififi.config.AppConfig;
import com.unififi.demo.model.User; import com.unififi.api.UserApi;
import com.unififi.demo.service.UserService; import com.unififi.model.User;
import com.unififi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit;
@RestController @RestController
@Slf4j
public class Demo1Controller { public class Demo1Controller {
@Autowired @Autowired
private RestTemplate restTemplate; private RestTemplate restTemplate;
@Autowired @Autowired
private UserService userService; private StringRedisTemplate stringRedisTemplate;
@Autowired
private UserApi userApi;
@Autowired @Autowired
private AppConfig appConfig; private AppConfig appConfig;
@Autowired
private LoadBalancerClient loadBalancer;
@Autowired
private UserService userService;
@GetMapping("/echo/{string}") @GetMapping("/echo/{string}")
public String echo(@PathVariable String string) { public String echo(@PathVariable String string) {
...@@ -34,11 +48,12 @@ public class Demo1Controller { ...@@ -34,11 +48,12 @@ public class Demo1Controller {
@GetMapping("/user/get") @GetMapping("/user/get")
public User userGet(@RequestParam("name") String name) { public User userGet(@RequestParam("name") String name) {
return userService.get(name); return userApi.get(name);
} }
@GetMapping(value = "/user/list") @GetMapping(value = "/user/list")
public List<User> userList() { public List<User> userList() {
// return userApi.list();
return restTemplate.getForObject("http://unififi-demo2-service/user/list", List.class); return restTemplate.getForObject("http://unififi-demo2-service/user/list", List.class);
} }
...@@ -58,4 +73,22 @@ public class Demo1Controller { ...@@ -58,4 +73,22 @@ public class Demo1Controller {
} }
return "ok"; return "ok";
} }
@GetMapping("/lb")
public String lb() {
ServiceInstance choose = loadBalancer.choose("unififi-demo2-service");
log.info(choose.toString());
return choose.getHost() + ":" + choose.getPort();
}
@PostMapping("/redis/set")
public Boolean redisSet(String name, String value) {
stringRedisTemplate.opsForValue().set(name, value, 1, TimeUnit.MINUTES);
return Boolean.TRUE;
}
@GetMapping("/redis/get")
public String redisGet(String name) {
return stringRedisTemplate.opsForValue().get(name);
}
} }
package com.unififi.demo.mapper; package com.unififi.mapper;
import com.unififi.demo.entity.DemoUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.unififi.entity.DemoUser;
public interface DemoUserMapper extends BaseMapper<DemoUser> { public interface DemoUserMapper extends BaseMapper<DemoUser> {
......
package com.unififi.service;
import com.unififi.model.User;
import java.util.List;
public interface UserService {
Boolean add(User user);
List<User> list();
}
package com.unififi.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.unififi.entity.DemoUser;
import com.unififi.mapper.DemoUserMapper;
import com.unififi.model.User;
import com.unififi.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
private DemoUserMapper demoUserMapper;
@Override
public Boolean add(com.unififi.model.User user) {
DemoUser demoUserEntity = new DemoUser();
demoUserEntity.setName(user.getName());
demoUserEntity.setAge(user.getAge());
int insert = demoUserMapper.insert(demoUserEntity);
log.info("user add. tostring:{} {}", user.toString(), insert);
return true;
}
@Override
public List<User> list() {
IPage<DemoUser> userPage = new Page<>();
List<User> list = new ArrayList<>();
QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
userPage = demoUserMapper.selectPage(userPage, queryWrapper);
log.info(JSON.toJSONString(userPage));
for (DemoUser userEntity : userPage.getRecords()) {
User user = new User();
BeanUtils.copyProperties(userEntity, user);
list.add(user);
}
return list;
}
}
package com.unififi.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* redis 工具类
*
* @author simon
* @date 2018-11-28 10:35
**/
@Component
public class RedisUtil {
/**
* 注入redisTemplate bean
*/
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
// ============================String(字符串)=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ================================Hash(哈希)=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================Set(集合)=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================List(列表)=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
\ No newline at end of file
server: #server:
port: 18081 # port: 18081
management: # compression:
endpoints: # enabled: true
web: # min-response-size: 2048
exposure: # mime-types: 'application/json'
include: '*' # endpoints:
spring: # web:
application: # exposure:
name: unififi-demo1-service # include: '*'
cloud: #spring:
# loadbalancer: # profiles:
# retry: # active: dev
# enabled: true # 开启Spring Cloud的重试功能 # application:
sentinel: # name: unififi-demo1-service
transport: #
dashboard: 39.106.6.97:8849 #feign:
# datasource: # httpclient:
# flow: # enabled: true
# nacos: # max-connections: 20
# server-addr: localhost:8848 # max-connections-per-route: 5
# dataId: ${spring.application.name}-flow-rules # time-to-live: 90
# groupId: SENTINEL_GROUP # connection-timeout: 3999
# # 规则类型,取值见: # connection-timer-repeat: 30000
# # org.springframework.cloud.alibaba.sentinel.datasource.RuleType # compression:
# rule-type: flow # request:
# degrade: # enabled: true
# nacos: # mime-types: application/json
# server-addr: localhost:8848 # min-request-size: 1024
# dataId: ${spring.application.name}-degrade-rules # response:
# groupId: SENTINEL_GROUP # enabled: true
# rule-type: degrade # useGzipDecoder: true
# system: # client:
# nacos: # config:
# server-addr: localhost:8848 # default:
# dataId: ${spring.application.name}-system-rules # connectTimeout: 2000
# groupId: SENTINEL_GROUP # readTimeout: 2000
# rule-type: system # loggerLevel: full
# authority: # unififi-demo2-service:
# nacos: # connectTimeout: 2001
# server-addr: localhost:8848 # readTimeout: 2001
# dataId: ${spring.application.name}-authority-rules # loggerLevel: basic
# groupId: SENTINEL_GROUP #
# rule-type: authority #logging:
# param-flow: # level:
# nacos: # com.unififi.demo.service.UserApi: DEBUG
# server-addr: localhost:8848 # com.alibaba.nacos.client.config.impl.ClientWorker: WARN
# dataId: ${spring.application.name}-param-flow-rules #
# groupId: SENTINEL_GROUP
# rule-type: param-flow
feign:
sentinel:
enabled: true
compression:
request:
enabled: true
mime-types: application/json
min-request-size: 2048
response:
enabled: true
useGzipDecoder: true
client:
config:
default:
connectTimeout: 2000
readTimeout: 3000
loggerLevel: full
logging:
level:
com.unififi.demo.service.UserService: DEBUG
#ribbon: #ribbon:
# OkToRetryOnAllOperations: true ## restclient:
# MaxAutoRetries: 1 #重试次数 ## enabled: true
# MaxAutoRetriesNextServer: 0 #重试切换实例次数 # eager-load:
# ConnectTimeout: 2000 # enabled: true
# ReadTimeout: 3000 # clients: unififi-demo2-service
# retryableStatusCodes: 503,500 # 这里不配置其实也可以,不配置的时候,仅仅当请求服务实例报错的时候重试,配置了的时候,当请求服务实例出现这里指定的状态,也会重试 # ConnectTimeout: 2002
\ No newline at end of file # ReadTimeout: 2002
# MaxAutoRetries: 0
# MaxAutoRetriesNextServer: 1
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
# retryableStatusCodes: 503,500
#unififi-demo2-service:
# ribbon:
# ConnectTimeout: 2003
# ReadTimeout: 2003
# MaxAutoRetries: 1
# MaxAutoRetriesNextServer: 2
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
# retryableStatusCodes: 503,500,501
server:
shutdown
port: 18081
compression:
enabled: true
min-response-size: 2048
mime-types: 'application/json'
endpoints:
web:
exposure:
include: '*'
spring: spring:
profiles:
active: dev
application:
name: unififi-demo1-service
cloud: cloud:
nacos: nacos:
username: nacos username: nacos
password: nacos password: nacos
server-addr: 39.106.6.97:8848 #server-addr: 39.106.6.97:8848
server-addr: localhost:8848
config: config:
file-extension: yaml
shared-configs: shared-configs:
- data-id: unififi-common.properties - data-id: unififi-common.yaml
refresh: false refresh: false
group: DEFAULT_GROUP group: DEFAULT_GROUP
extension-configs: - data-id: unififi-redis.yaml
- refresh: true refresh: false
data-id: unififi-ext.properties group: DEFAULT_GROUP
- data-id: unififi-jdbc.yaml
refresh: false
group: DEFAULT_GROUP group: DEFAULT_GROUP
discovery:
metadata:
unififi.mode: ${unififi.mode}
unififi.service.version: '@unififi-service.version@'
user.home: ${user.home}
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<springProperty scope="context" name="logPath" source="unififi.logs.path" defaultValue="${user.home}/logs"/>
<property name="LOG_HOME" value="${logPath}"/>
<property name="APP_NAME" value="unififi-demo1-service"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/${APP_NAME}/${APP_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>365</MaxHistory>
</rollingPolicy>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level - %msg%n</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 丢弃日志临界值。默认20%,队列容量小于临界值则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 队列大小。默认值为256 -->
<queueSize>1024</queueSize>
<!-- 队列满时不阻塞。默认false,线程阻塞 -->
<neverBlock>true</neverBlock>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="FILE"/>
</appender>
<logger name="org.springframework" level="WARN"/>
<!-- 开发环境输出到控制台 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<root level="INFO">
<appender-ref ref="ASYNC"/>
</root>
</configuration>
...@@ -35,6 +35,25 @@ ...@@ -35,6 +35,25 @@
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<exclusions>
<exclusion>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hystrix</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.7.4</version>
</dependency>
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.alibaba</groupId>
<artifactId>druid</artifactId> <artifactId>druid</artifactId>
...@@ -50,11 +69,7 @@ ...@@ -50,11 +69,7 @@
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version> <version>5.1.49</version>
</dependency> </dependency>
<dependency> <!-- mybatis代码生成 -->
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId> <artifactId>mybatis-plus-generator</artifactId>
...@@ -65,6 +80,22 @@ ...@@ -65,6 +80,22 @@
<artifactId>freemarker</artifactId> <artifactId>freemarker</artifactId>
<version>2.3.30</version> <version>2.3.30</version>
</dependency> </dependency>
<!-- redis配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
......
package com.unififi.demo; package com.unififi;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@MapperScan("com.unififi.mapper")
@SpringBootApplication @SpringBootApplication
@EnableDiscoveryClient @EnableDiscoveryClient
public class Demo2Application { public class Demo2Application {
......
package com.unififi.demo.config; package com.unififi.config;
import lombok.Getter; import lombok.Getter;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
......
package com.unififi.demo.config; package com.unififi.config;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringPool;
......
package com.unififi.demo.config; package com.unififi.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
...@@ -11,13 +12,16 @@ import java.util.Map; ...@@ -11,13 +12,16 @@ import java.util.Map;
/** /**
* 统一异常处理 * 统一异常处理
*/ */
@Slf4j
@RestControllerAdvice @RestControllerAdvice
public class ControllerExceptionHandler { public class ControllerExceptionHandler {
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public Map handleException(Exception e) { public Map handleException(Exception e) {
Map map = new HashMap(); Map map = new HashMap();
map.put("code", 500); map.put("code", 500);
map.put("msg", e.getMessage()); map.put("msg", e.getMessage());
log.error("Exception: ",e);
return map; return map;
} }
...@@ -26,6 +30,7 @@ public class ControllerExceptionHandler { ...@@ -26,6 +30,7 @@ public class ControllerExceptionHandler {
Map map = new HashMap(); Map map = new HashMap();
map.put("code", 501); map.put("code", 501);
map.put("msg", e.getMessage()); map.put("msg", e.getMessage());
log.error("HttpRequestMethodNotSupportedException: ",e);
return map; return map;
} }
...@@ -35,6 +40,7 @@ public class ControllerExceptionHandler { ...@@ -35,6 +40,7 @@ public class ControllerExceptionHandler {
MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e; MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
map.put("code", 502); map.put("code", 502);
map.put("msg", exception.getBindingResult().getAllErrors().get(0).getDefaultMessage()); map.put("msg", exception.getBindingResult().getAllErrors().get(0).getDefaultMessage());
log.error("MethodArgumentNotValidException: ",e);
return map; return map;
} }
} }
package com.unififi.demo.config; package com.unififi.config;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.serializer.SerializerFeature;
...@@ -12,7 +12,6 @@ import org.springframework.context.annotation.Configuration; ...@@ -12,7 +12,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage; import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.http.converter.HttpMessageNotWritableException;
...@@ -28,9 +27,7 @@ public class HttpMessageConverterConfig { ...@@ -28,9 +27,7 @@ public class HttpMessageConverterConfig {
@Bean @Bean
public HttpMessageConverters fastJsonHttpMessageConverters() { public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new UheFastJsonHttpMessageConverter(); FastJsonHttpMessageConverter fastConverter = new UheFastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig(); FastJsonConfig fastJsonConfig = new FastJsonConfig();
SerializerFeature[] serializerFeatures = new SerializerFeature[]{ SerializerFeature[] serializerFeatures = new SerializerFeature[]{
// Date的日期转换器 // Date的日期转换器
SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteDateUseDateFormat,
...@@ -47,9 +44,7 @@ public class HttpMessageConverterConfig { ...@@ -47,9 +44,7 @@ public class HttpMessageConverterConfig {
fastjsonSupportedMediaTypes.add(MediaType.APPLICATION_JSON); fastjsonSupportedMediaTypes.add(MediaType.APPLICATION_JSON);
fastConverter.setSupportedMediaTypes(fastjsonSupportedMediaTypes); fastConverter.setSupportedMediaTypes(fastjsonSupportedMediaTypes);
HttpMessageConverter<?> converter = fastConverter; return new HttpMessageConverters(fastConverter);
return new HttpMessageConverters(converter);
} }
private static class UheFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter { private static class UheFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
......
package com.unififi.config;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.ArrayList;
import java.util.List;
@EnableTransactionManagement
@Configuration
@MapperScan(basePackages = {"com.unififi.mapper"})
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setOverflow(false);
paginationInterceptor.setLimit(2);
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
List<ISqlParser> sqlParserList = new ArrayList<>();
// 攻击 SQL 阻断解析器、加入解析链
sqlParserList.add(new BlockAttackSqlParser());
paginationInterceptor.setSqlParserList(sqlParserList);
return paginationInterceptor;
}
}
\ No newline at end of file
package com.unififi.config;
import org.apache.http.client.HttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
httpComponentsClientHttpRequestFactory.setReadTimeout(5000);
httpComponentsClientHttpRequestFactory.setConnectTimeout(30000);
return httpComponentsClientHttpRequestFactory;
}
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory httpRequestFactory) {
BufferingClientHttpRequestFactory bufferingClientHttpRequestFactory = new BufferingClientHttpRequestFactory(httpRequestFactory);
RestTemplate restTemplate = new RestTemplate(bufferingClientHttpRequestFactory);
restTemplate.getInterceptors().add(new UnififiRestTemplateLogInterceptor());
return restTemplate;
}
// @Bean
// public ClientHttpRequestFactory httpRequestFactory(HttpClient httpClient) {
// return new HttpComponentsClientHttpRequestFactory(httpClient);
// }
// @Bean
// public RestTemplateCustomizer restTemplateCustomizer(
// final ClientHttpRequestFactory requestFactory) {
// return restTemplate -> restTemplate
// .setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
// }
}
package com.unififi.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
public class UnififiRestTemplateLogInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(UnififiRestTemplateLogInterceptor.class);
public static final Charset UTF_8 = Charset.forName("UTF-8");
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
String methodTag = getMethodTag(request.getURI());
if (logger.isInfoEnabled()) {
logger.info("REST-REQ-[{}] {} --> {} {}", methodTag, body != null ? new String(body, UTF_8) : "", request.getMethod(), request.getURI());
}
long start = System.nanoTime();
ClientHttpResponse response = null;
try {
response = execution.execute(request, body);
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
if (logger.isInfoEnabled()) {
StringBuilder inputStringBuilder = new StringBuilder();
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(response.getBody(), UTF_8))) {
String line = bufferedReader.readLine();
while (line != null) {
inputStringBuilder.append(line);
line = bufferedReader.readLine();
if (line != null) {
inputStringBuilder.append('\n');
}
}
}
logger.info("REST-RESP-[{}] {} {}ms", methodTag, inputStringBuilder.toString(), elapsedTime);
}
} catch (IOException ioe) {
logger.error("REST-RESP-[{}] {}: {}", methodTag, ioe.getClass().getSimpleName(), ioe.getMessage());
throw ioe;
}
return response;
}
private String getMethodTag(URI uri) {
try {
if (uri.getPath().indexOf('?') > -1) {
return uri.getPath().substring(0, uri.getPath().indexOf('?'));
} else {
return uri.getPath();
}
} catch (Exception e) {
return uri.getPath();
}
}
}
package com.unififi.demo.controller; package com.unififi.controller;
import com.unififi.demo.model.User; import com.unififi.config.AppConfig;
import com.unififi.demo.service.UserService; import com.unififi.api.UserApi;
import com.unififi.model.User;
import com.unififi.service.UserService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -10,32 +12,50 @@ import org.springframework.web.bind.annotation.*; ...@@ -10,32 +12,50 @@ import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
@RestController @RestController
public class Demo2Controller { public class Demo2Controller implements UserApi {
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired
private AppConfig appConfig;
@Override
@RequestMapping(value = "/echo/{string}", method = RequestMethod.GET) @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
public String echo(@PathVariable String string) { public String echo(@PathVariable String string) {
return userService.echo(string); return userService.echo(string);
} }
@Override
@PostMapping(value = "/user/add", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) @PostMapping(value = "/user/add", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public Boolean add(@RequestBody User user) { public Boolean add(@RequestBody User user) {
return userService.add(user); return userService.add(user);
} }
@Override
@RequestMapping(value = "/user/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @RequestMapping(value = "/user/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<User> list() throws InterruptedException { public List<User> list() {
Thread.sleep(5000L); try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return userService.list(); return userService.list();
} }
@GetMapping("/user/get") @Override
public User get(@RequestParam("name") String name) throws InterruptedException { @GetMapping(value = "/user/get", produces = MediaType.APPLICATION_JSON_VALUE)
Thread.sleep(5000L); public User get(@RequestParam("name") String name) {
System.out.println("user/get " + name); System.out.println("user/get " + name);
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
return userService.get(name); return userService.get(name);
} }
@GetMapping("/config/username")
public String get() throws InterruptedException {
return appConfig.getUsername();
}
} }
package com.unififi.entity;
import lombok.Data;
@Data
public class DemoUser {
private static final long serialVersionUID = 1L;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 邮箱
*/
private String email;
}
package com.unififi.mapper;
import com.unififi.entity.DemoUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface DemoUserMapper extends BaseMapper<DemoUser> {
}
package com.unififi.service;
import com.unififi.model.User;
import java.util.List;
public interface UserService {
String echo(String string);
List<User> list();
User get(String name);
Boolean add(User user);
}
package com.unififi.demo.service.impl; package com.unififi.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.unififi.demo.entity.DemoUser; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.unififi.demo.mapper.DemoUserMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.unififi.demo.model.User; import com.unififi.entity.DemoUser;
import com.unififi.demo.service.UserService; import com.unififi.mapper.DemoUserMapper;
import com.unififi.model.User;
import com.unififi.service.UserService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
@Service @Service
...@@ -20,18 +27,39 @@ public class UserServiceImpl implements UserService { ...@@ -20,18 +27,39 @@ public class UserServiceImpl implements UserService {
@Autowired @Autowired
private DemoUserMapper demoUserMapper; private DemoUserMapper demoUserMapper;
@Autowired
private RestTemplate restTemplate;
@Override @Override
public String echo(String string) { public String echo(String string) {
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_JSON);
header.add("Authorization", "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjMwODFiNDYzLTAxMDQtNGRhNC04M2ViLWFiNDlmNzJkM2M4NSJ9.M4yeJqyrcOPZ7JUcGjhXgB4qyJh7s3MIfbu8K2TS2Mv1BZH6T9YnEBcdV3qfFWjicY8GddwB5H3sKAj1QCQ8xQ");
Map<String, String> param = new HashMap<>();
param.put("perms", "refund:refundList");
HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(param, header);
String url = "http://www.unififi.com/u2c-basic-service/getInfo";
ResponseEntity<Object> exchange = null;
try {
exchange = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Object.class);
} catch (Exception e) {
e.printStackTrace();
}
return "unififi-demo2-service echo: " + string; return "unififi-demo2-service echo: " + string;
} }
@Override @Override
public List<User> list() { public List<User> list() {
IPage<DemoUser> userPage = new Page<>();
List<User> list = new ArrayList<>(); List<User> list = new ArrayList<>();
QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>(); QueryWrapper<DemoUser> queryWrapper = new QueryWrapper<>();
List<DemoUser> demoUsers = demoUserMapper.selectList(queryWrapper); userPage = demoUserMapper.selectPage(userPage, queryWrapper);
log.info("user list. size:" + demoUsers.size()); log.info(JSON.toJSONString(userPage));
for (DemoUser userEntity : demoUsers) { for (DemoUser userEntity : userPage.getRecords()) {
User user = new User(); User user = new User();
BeanUtils.copyProperties(userEntity, user); BeanUtils.copyProperties(userEntity, user);
list.add(user); list.add(user);
......
server: #server:
port: 18080 # port: 18080
management: #management:
endpoints: # endpoints:
web: # web:
exposure: # exposure:
include: '*' # include: '*'
spring: #spring:
application: # profiles:
name: unififi-demo2-service # active: dev
datasource: # application:
driver-class-name: com.mysql.jdbc.Driver # name: unififi-demo2-service
url: jdbc:mysql://39.106.6.97:3306/unififi_spring_cloud_guide?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC # datasource:
username: unififi # driver-class-name: com.mysql.jdbc.Driver
password: YQA6o9pw1r # #url: jdbc:mysql://39.106.6.97:3306/unififi_spring_cloud_guide?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
druid: # #username: unififi
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 # #password: YQA6o9pw1r
filters: config,wall,stat # url: jdbc:mysql://localhost:3306/unififi_spring_cloud_guide?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
# 初始化数量 # username: root
initialSize: 5 # password: root
# 最小连接池数量 # druid:
minIdle: 5 # # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
# 最大连接池数量 # filters: config,wall,stat
maxActive: 20 # # 初始化数量
# 连接超时时间 # initialSize: 5
maxWait: 60000 # # 最小连接池数量
# 打开psCache, 对支持游标的数据库性能提升巨大 # minIdle: 5
poolPreparedStatements: true # # 最大连接池数量
# 指定每个连接PsCache的大小 # maxActive: 20
maxPoolPreparedStatementPerConnectionSize: 20 # # 连接超时时间
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 # maxWait: 60000
timeBetweenEvictionRunsMillis: 60000 # # 打开psCache, 对支持游标的数据库性能提升巨大
# 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒 # poolPreparedStatements: true
minEvictableIdleTimeMillis: 300000 # # 指定每个连接PsCache的大小
# 验证数据库连接的查询语句 # maxPoolPreparedStatementPerConnectionSize: 20
validationQuery: select 1 # # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
# 当连接空闲时,是否执行连接测试 # timeBetweenEvictionRunsMillis: 60000
testWhileIdle: true # # 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒
# 当从连接池借用连接时,是否测试该连接 # minEvictableIdleTimeMillis: 300000
testOnBorrow: false # # 验证数据库连接的查询语句
# 在连接归还到连接池时是否测试该连接 # validationQuery: select 1
testOnReturn: false # # 当连接空闲时,是否执行连接测试
# 打开mergeSql,慢sql记录 # testWhileIdle: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 # # 当从连接池借用连接时,是否测试该连接
# testOnBorrow: false
# # 在连接归还到连接池时是否测试该连接
# testOnReturn: false
# # 打开mergeSql,慢sql记录
# connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
## redis:
## database: 0
## host: localhost
## port: 13350
## # 连接超时时间
## timeout: 5000
## lettuce:
## pool:
## # 连接池最大连接数,默认8
## max-active: 8
## # 连接池中的最大空闲连接,默认8
## max-idle: 8
## # 连接池中的最小空闲连接,默认0
## min-idle: 5
## # 连接池最大阻塞等待时间,默认-1
## max-wait:
\ No newline at end of file
server:
port: 18080
management:
endpoints:
web:
exposure:
include: '*'
spring: spring:
profiles:
active: dev
application:
name: unififi-demo2-service
cloud: cloud:
nacos: nacos:
username: nacos username: nacos
password: nacos password: nacos
server-addr: 39.106.6.97:8848 #server-addr: 39.106.6.97:8848
server-addr: localhost:8848
config: config:
file-extension: yaml
shared-configs: shared-configs:
- data-id: unififi-common.properties - data-id: unififi-common.yaml
refresh: false refresh: false
group: DEFAULT_GROUP group: DEFAULT_GROUP
extension-configs: - data-id: unififi-redis.yaml
- refresh: true refresh: false
data-id: unififi-ext.properties group: DEFAULT_GROUP
- data-id: unififi-jdbc.yaml
refresh: false
group: DEFAULT_GROUP group: DEFAULT_GROUP
discovery:
metadata:
unififi.mode: ${unififi.mode}
unififi.service.version: '@unififi-service.version@'
user.home: ${user.home}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="/data/log/java_web"/>
<property name="APP_NAME" value="unififi-demo2-service"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/${APP_NAME}/${APP_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>365</MaxHistory>
</rollingPolicy>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level - %msg%n</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 丢弃日志临界值。默认20%,队列容量小于临界值则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 队列大小。默认值为256 -->
<queueSize>1024</queueSize>
<!-- 队列满时不阻塞。默认false,线程阻塞 -->
<neverBlock>true</neverBlock>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="FILE"/>
</appender>
<logger name="org.springframework" level="WARN"/>
<!-- 开发环境输出到控制台 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<!-- 生产环境输出到文件 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ASYNC"/>
</root>
</springProfile>
</configuration>
...@@ -29,26 +29,26 @@ ...@@ -29,26 +29,26 @@
<groupId>com.alibaba.cloud</groupId> <groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>com.alibaba.cloud</groupId> <!-- <groupId>com.alibaba.cloud</groupId>-->
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <!-- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>-->
</dependency> <!-- </dependency>-->
<dependency> <!-- <dependency>-->
<groupId>com.alibaba.cloud</groupId> <!-- <groupId>com.alibaba.cloud</groupId>-->
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> <!-- <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>-->
</dependency> <!-- </dependency>-->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId> <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>com.alibaba.csp</groupId> <!-- <groupId>com.alibaba.csp</groupId>-->
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> <!-- <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>-->
</dependency> <!-- </dependency>-->
<dependency> <!-- <dependency>-->
<groupId>com.alibaba.csp</groupId> <!-- <groupId>com.alibaba.csp</groupId>-->
<artifactId>sentinel-core</artifactId> <!-- <artifactId>sentinel-core</artifactId>-->
</dependency> <!-- </dependency>-->
<!-- <dependency>--> <!-- <dependency>-->
<!-- <groupId>com.alibaba.csp</groupId>--> <!-- <groupId>com.alibaba.csp</groupId>-->
<!-- <artifactId>sentinel-datasource-nacos</artifactId>--> <!-- <artifactId>sentinel-datasource-nacos</artifactId>-->
......
...@@ -4,7 +4,9 @@ package com.unififi.gateway; ...@@ -4,7 +4,9 @@ package com.unififi.gateway;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication @SpringBootApplication
@EnableFeignClients @EnableFeignClients
public class GatewayApplication { public class GatewayApplication {
......
package com.unififi.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
public class AuthenticationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
chain.filter(exchange)
.then(Mono.just(exchange))
.map(serverWebExchange -> {
//adds header to response
serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
return serverWebExchange;
})
.then();
return null;
}
}
...@@ -7,19 +7,19 @@ management: ...@@ -7,19 +7,19 @@ management:
include: '*' include: '*'
spring: spring:
profiles:
active: dev
application: application:
name: unififi-gateway name: unififi-gateway
cloud: cloud:
sentinel:
filter:
enabled: true
transport:
dashboard: 39.106.6.97:8849
gateway: gateway:
httpclient:
connect-timeout: 3000
response-timeout: 30000
enabled: true enabled: true
discovery: discovery:
locator: locator:
lower-case-service-id: true enabled: true
routes: routes:
- id: unififi-demo1-service-route - id: unififi-demo1-service-route
uri: lb://unififi-demo1-service/ uri: lb://unififi-demo1-service/
...@@ -32,4 +32,10 @@ spring: ...@@ -32,4 +32,10 @@ spring:
predicates: predicates:
- Path=/demo2/** - Path=/demo2/**
filters: filters:
- StripPrefix=1 - StripPrefix=1
\ No newline at end of file metadata:
connect-timeout: 5000
response-timeout: 30000
unififi-demo2-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
\ No newline at end of file
...@@ -3,4 +3,4 @@ spring: ...@@ -3,4 +3,4 @@ spring:
nacos: nacos:
username: nacos username: nacos
password: nacos password: nacos
server-addr: 39.106.6.97:8848 server-addr: localhost:8848
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="/data/log/java_web"/>
<property name="APP_NAME" value="unififi-gateway-service"/>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/${APP_NAME}/${APP_NAME}.%d{yyyy-MM-dd}.log</FileNamePattern>
<MaxHistory>365</MaxHistory>
</rollingPolicy>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level - %msg%n</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 丢弃日志临界值。默认20%,队列容量小于临界值则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 队列大小。默认值为256 -->
<queueSize>1024</queueSize>
<!-- 队列满时不阻塞。默认false,线程阻塞 -->
<neverBlock>true</neverBlock>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="FILE"/>
</appender>
<appender name="accessLog" class="ch.qos.logback.core.FileAppender">
<file>${LOG_HOME}/${APP_NAME}/access_log.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
<appender-ref ref="accessLog"/>
</logger>
<logger name="org.springframework" level="WARN"/>
<!-- 开发环境输出到控制台 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</springProfile>
<!-- 生产环境输出到文件 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ASYNC"/>
</root>
</springProfile>
</configuration>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment