Browse Source

新增代码

master
liuchen 8 months ago
commit
4f87766aba
  1. 33
      .gitignore
  2. 66
      pom.xml
  3. 18
      src/main/java/com/win/mq/Application.java
  4. 112
      src/main/java/com/win/mq/common/CommonResult.java
  5. 28
      src/main/java/com/win/mq/config/RMQConfigure.java
  6. 31
      src/main/java/com/win/mq/config/RestTemplateConfig.java
  7. 34
      src/main/java/com/win/mq/config/SmfsConfigure.java
  8. 98
      src/main/java/com/win/mq/controller/ProduceController.java
  9. 26
      src/main/java/com/win/mq/exception/ErrorCode.java
  10. 44
      src/main/java/com/win/mq/exception/GlobalErrorCodeConstants.java
  11. 58
      src/main/java/com/win/mq/exception/ServerException.java
  12. 58
      src/main/java/com/win/mq/exception/ServiceException.java
  13. 52
      src/main/java/com/win/mq/rocket/RocketMQConsumer.java
  14. 26
      src/main/java/com/win/mq/rocket/RocketMQProducer.java
  15. 64
      src/main/java/com/win/mq/utils/FileUtil.java
  16. 26
      src/main/java/com/win/mq/utils/ProfileUtil.java
  17. 105
      src/main/java/com/win/mq/utils/sfms/AccessTokenUtil.java
  18. 46
      src/main/java/com/win/mq/utils/sfms/AccessTokenVO.java
  19. 33
      src/main/java/com/win/mq/utils/sfms/RefreshTokenVO.java
  20. 38
      src/main/resources/application-dev.yml
  21. 12
      src/main/resources/application.yml
  22. 108
      src/main/resources/logback-spring.xml
  23. 13
      src/test/java/com/win/mq/MqApplicationTests.java

33
.gitignore

@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### 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/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

66
pom.xml

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.win.mq</groupId>
<artifactId>mq</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mq</name>
<description>win mq</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.2</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

18
src/main/java/com/win/mq/Application.java

@ -0,0 +1,18 @@
package com.win.mq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* 启动程序
*
* @author win
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
System.out.println("闻音启动成功");
}
}

112
src/main/java/com/win/mq/common/CommonResult.java

@ -0,0 +1,112 @@
package com.win.mq.common;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.win.mq.exception.ErrorCode;
import com.win.mq.exception.GlobalErrorCodeConstants;
import com.win.mq.exception.ServiceException;
import lombok.Data;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.Objects;
/**
* 通用返回
*
* @param <T> 数据泛型
*/
@Data
public class CommonResult<T> implements Serializable {
/**
* 错误码
*
* @see ErrorCode#getCode()
*/
private Integer code;
/**
* 返回数据
*/
private T data;
/**
* 错误提示用户可阅读
*
* @see ErrorCode#getMsg() ()
*/
private String msg;
/**
* 将传入的 result 对象转换成另外一个泛型结果的对象
*
* 因为 A 方法返回的 CommonResult 对象不满足调用其的 B 方法的返回所以需要进行转换
*
* @param result 传入的 result 对象
* @param <T> 返回的泛型
* @return 新的 CommonResult 对象
*/
public static <T> CommonResult<T> error(CommonResult<?> result) {
return error(result.getCode(), result.getMsg());
}
public static <T> CommonResult<T> error(Integer code, String message) {
Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!");
CommonResult<T> result = new CommonResult<>();
result.code = code;
result.msg = message;
return result;
}
public static <T> CommonResult<T> error(ErrorCode errorCode) {
return error(errorCode.getCode(), errorCode.getMsg());
}
public static <T> CommonResult<T> success(T data) {
CommonResult<T> result = new CommonResult<>();
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
result.data = data;
result.msg = "";
return result;
}
public static boolean isSuccess(Integer code) {
return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
}
@JsonIgnore // 避免 jackson 序列化
public boolean isSuccess() {
return isSuccess(code);
}
@JsonIgnore // 避免 jackson 序列化
public boolean isError() {
return !isSuccess();
}
// ========= 和 Exception 异常体系集成 =========
/**
* 判断是否有异常如果有则抛出 {@link ServiceException} 异常
*/
public void checkError() throws ServiceException {
if (isSuccess()) {
return;
}
// 业务异常
throw new ServiceException(code, msg);
}
/**
* 判断是否有异常如果有则抛出 {@link ServiceException} 异常
* 如果没有则返回 {@link #data} 数据
*/
@JsonIgnore // 避免 jackson 序列化
public T getCheckedData() {
checkError();
return data;
}
public static <T> CommonResult<T> error(ServiceException serviceException) {
return error(serviceException.getCode(), serviceException.getMessage());
}
}

28
src/main/java/com/win/mq/config/RMQConfigure.java

@ -0,0 +1,28 @@
package com.win.mq.config;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.common.MixAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import java.io.File;
import static org.apache.rocketmq.client.ClientConfig.SEND_MESSAGE_WITH_VIP_CHANNEL_PROPERTY;
@Data
@Configuration
@ConfigurationProperties(prefix = "rocketmq.config")
public class RMQConfigure {
private String dataPath;
}

31
src/main/java/com/win/mq/config/RestTemplateConfig.java

@ -0,0 +1,31 @@
package com.win.mq.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 支持中文编码
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
return restTemplate;
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);//单位为ms
factory.setConnectTimeout(5000);//单位为ms
return factory;
}
}

34
src/main/java/com/win/mq/config/SmfsConfigure.java

@ -0,0 +1,34 @@
package com.win.mq.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "sfms")
public class SmfsConfigure {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 采购订单请求地址
*/
private String purchaseOrder;
/**
* 访问token
*/
private String accessToken;
/**
* 刷新token
*/
private String refreshToken;
}

98
src/main/java/com/win/mq/controller/ProduceController.java

@ -0,0 +1,98 @@
package com.win.mq.controller;
import com.win.mq.common.CommonResult;
import com.win.mq.config.RMQConfigure;
import com.win.mq.exception.GlobalErrorCodeConstants;
import com.win.mq.rocket.RocketMQProducer;
import com.win.mq.utils.FileUtil;
import com.win.mq.utils.ProfileUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/producer")
public class ProduceController {
@Autowired
private RMQConfigure configure;
@Autowired
private FileUtil fileUtil;
@Autowired
private RocketMQProducer rocketMQProducer;
/**
* 对外提供一个接口通过header中的interfaceName反射机制调用方法方法必须写到这个controller中并且不用加PostMapping注解
*
* @param request request
* @param body 请求主体
* @return 结果
*/
@PostMapping("/api")
@SuppressWarnings("unchecked")
public CommonResult<String> api(HttpServletRequest request, @RequestBody String body) {
String interfaceName = request.getHeader("interface");
String sign = request.getHeader("sign");
String timeStr = request.getHeader("timestamp");
if(timeStr == null || timeStr.isEmpty()) {
return CommonResult.error(GlobalErrorCodeConstants.TIMESTAMP_ERROR);
}
long timestamp = 0;
try {
timestamp = Long.parseLong(timeStr);
} catch (NumberFormatException e) {
return CommonResult.error(GlobalErrorCodeConstants.TIMESTAMP_ERROR);
}
String tmp = interfaceName + body + timestamp;
String computeSign = DigestUtils.md5DigestAsHex(tmp.getBytes());
log.info("{}, interfaceName: {}", "interfaceName", interfaceName);
log.info("{}, sign: {}", "sign", sign);
log.info("{}, timestamp: {}", "timestamp", timestamp);
log.info("{}, tmp: {}", "tmp", tmp);
log.info("{}, computeSign: {}", "computeSign", computeSign);
long tenTimestamp = timestamp + (10 * 60 * 1000); // 计算10分钟后的时间戳
long currentTimestamp = System.currentTimeMillis(); // 获取当前时间戳
//过期
if(timestamp > currentTimestamp || tenTimestamp < currentTimestamp) {
return CommonResult.error(GlobalErrorCodeConstants.EXPIRE_ERROR);
}
List<String> activeProfile = ProfileUtil.getActiveProfile();
//dev环境不校验签名
if(!activeProfile.contains("dev") && !StringUtils.equals(sign, computeSign.toUpperCase())) {
return CommonResult.error(GlobalErrorCodeConstants.SIGN_ERROR);
}
try {
Method method = this.getClass().getMethod(interfaceName, String.class);
return (CommonResult<String>) method.invoke(this, body);
} catch (NoSuchMethodException e) {
return CommonResult.error(GlobalErrorCodeConstants.INTERFACE_ERROR);
} catch (Exception e) {
return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR);
}
}
public CommonResult<Object[]> order(String message) {
String[] tags = fileUtil.readTags("order.txt");
if(tags == null || tags.length == 0) {
return CommonResult.error(GlobalErrorCodeConstants.CONFIG_ERROR);
}
List<String> messageList = new ArrayList<>();
for(String tag : tags) {
String messageId = rocketMQProducer.sendMessage("order" + tag, message);
messageList.add(messageId);
}
return CommonResult.success(messageList.toArray());
}
}

26
src/main/java/com/win/mq/exception/ErrorCode.java

@ -0,0 +1,26 @@
package com.win.mq.exception;
import lombok.Data;
/**
* 错误码对象
* TODO 错误码设计成对象的原因为未来的 i18 国际化做准备
*/
@Data
public class ErrorCode {
/**
* 错误码
*/
private final Integer code;
/**
* 错误提示
*/
private final String msg;
public ErrorCode(Integer code, String message) {
this.code = code;
this.msg = message;
}
}

44
src/main/java/com/win/mq/exception/GlobalErrorCodeConstants.java

@ -0,0 +1,44 @@
package com.win.mq.exception;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
*
* 一般情况下使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说HTTP 响应状态码作为业务使用表达能力偏弱但是使用在系统层面还是非常不错的
* 比较特殊的是因为之前一直使用 0 作为成功就不使用 200
*
* @author 闻荫源码
*/
public interface GlobalErrorCodeConstants {
ErrorCode SUCCESS = new ErrorCode(0, "成功");
ErrorCode SIGN_ERROR = new ErrorCode(300, "签名不正确");
ErrorCode TIMESTAMP_ERROR = new ErrorCode(301, "时间戳不正确");
ErrorCode EXPIRE_ERROR = new ErrorCode(302, "请求已过期");
ErrorCode INTERFACE_ERROR = new ErrorCode(303, "接口不正确");
ErrorCode CONFIG_ERROR = new ErrorCode(304, "请先维护推送设置");
ErrorCode SEND_ERROR = new ErrorCode(305, "发送消息失败");
// ========== 客户端错误段 ==========
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
// ========== 服务端错误段 ==========
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
// ========== 自定义错误段 ==========
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
}

58
src/main/java/com/win/mq/exception/ServerException.java

@ -0,0 +1,58 @@
package com.win.mq.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 服务器异常 Exception
*/
@Data
@EqualsAndHashCode(callSuper = true)
public final class ServerException extends RuntimeException {
/**
* 全局错误码
*
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 空构造方法避免反序列化问题
*/
public ServerException() {
}
public ServerException(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMsg();
}
public ServerException(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public ServerException setCode(Integer code) {
this.code = code;
return this;
}
@Override
public String getMessage() {
return message;
}
public ServerException setMessage(String message) {
this.message = message;
return this;
}
}

58
src/main/java/com/win/mq/exception/ServiceException.java

@ -0,0 +1,58 @@
package com.win.mq.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 业务逻辑异常 Exception
*/
@Data
@EqualsAndHashCode(callSuper = true)
public final class ServiceException extends RuntimeException {
/**
* 业务错误码
*
*/
private Integer code;
/**
* 错误提示
*/
private String message;
/**
* 空构造方法避免反序列化问题
*/
public ServiceException() {
}
public ServiceException(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMsg();
}
public ServiceException(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public ServiceException setCode(Integer code) {
this.code = code;
return this;
}
@Override
public String getMessage() {
return message;
}
public ServiceException setMessage(String message) {
this.message = message;
return this;
}
}

52
src/main/java/com/win/mq/rocket/RocketMQConsumer.java

@ -0,0 +1,52 @@
package com.win.mq.rocket;
import com.win.mq.config.SmfsConfigure;
import com.win.mq.utils.sfms.AccessTokenUtil;
import com.win.mq.utils.sfms.AccessTokenVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Component
public class RocketMQConsumer {
@Autowired
private AccessTokenUtil accessTokenUtil;
@Autowired
private SmfsConfigure smfsConfigure;
@Autowired
private RestTemplate restTemplate;
@Component
@RocketMQMessageListener(topic = "order", consumerGroup = "wms", selectorExpression="wms")
class RocketMQConsumerWms implements RocketMQListener<String> {
public void onMessage(String message) {
//获取token,调用采购订单接口
//AccessTokenVO accessTokenVO = accessTokenUtil.getAccessTokenVO();
//log.info(accessTokenVO.toString());
//HttpHeaders headers = new HttpHeaders();
//headers.setContentType(MediaType.APPLICATION_JSON);
//headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + accessTokenVO.getAccessToken());
//headers.add("tenant-id", "1");
// 将JSON参数转换成HttpEntity对象
//HttpEntity<String> requestEntity = new HttpEntity<>(message, headers);
// 发起POST请求
//ResponseEntity<String> responseEntity = restTemplate.postForEntity(smfsConfigure.getPurchaseOrder(), requestEntity, String.class);
log.info("RocketMQConsumerWms received message: " + message);
}
}
@Component
@RocketMQMessageListener(topic = "order", consumerGroup = "scp", selectorExpression="scp")
class RocketMQConsumerScp implements RocketMQListener<String>/*, RocketMQPushConsumerLifecycleListener*/ {
public void onMessage(String message) {
log.info("RocketMQConsumerScp received message: " + message);
}
}
}

26
src/main/java/com/win/mq/rocket/RocketMQProducer.java

@ -0,0 +1,26 @@
package com.win.mq.rocket;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
public class RocketMQProducer {
@Autowired
private RocketMQTemplate rocketMQTemplate;
public String sendMessage(String topic, String message) {
long timeStamp = new Date().getTime();
SendResult sendResult = rocketMQTemplate.syncSendOrderly(topic, message + "_" + timeStamp, String.valueOf(timeStamp));
return sendResult.getMsgId();
}
}

64
src/main/java/com/win/mq/utils/FileUtil.java

@ -0,0 +1,64 @@
package com.win.mq.utils;
import com.win.mq.config.RMQConfigure;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
@Slf4j
@Component
public class FileUtil {
@Autowired
private RMQConfigure configure;
private String[] defaultTags;
public String[] readTags(String fileName) {
File file = new File(configure.getDataPath() + File.separator + fileName);
//默认不带标签
String[] tags = null;
if(file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(configure.getDataPath() + File.separator + fileName))) {
String line = reader.readLine();
tags = line.split(",");
for(int i = 0; i < tags.length; i++) {
String tag = tags[i];
tags[i] = ":" + tag;
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
return tags;
}
private String[] getDefaultTags() {
//不为空直接返回
if(this.defaultTags != null) {
return this.defaultTags;
}
File file = new File(configure.getDataPath() + File.separator + "project.txt");
if(file.exists()) {
String[] tags = null;
try (BufferedReader reader = new BufferedReader(new FileReader(configure.getDataPath() + File.separator + "project.txt"))) {
String line = reader.readLine();
tags = line.split(",");
for(int i = 0; i < tags.length; i++) {
String tag = tags[i];
tags[i] = ":" + tag;
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
this.defaultTags = tags;
return this.defaultTags;
} else {
return new String[]{""};
}
}
}

26
src/main/java/com/win/mq/utils/ProfileUtil.java

@ -0,0 +1,26 @@
package com.win.mq.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class ProfileUtil implements ApplicationContextAware {
private static ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
// 获取当前环境参数 exp: dev,prod,test
public static List<String> getActiveProfile() {
return Arrays.asList(context.getEnvironment().getActiveProfiles());
}
}

105
src/main/java/com/win/mq/utils/sfms/AccessTokenUtil.java

@ -0,0 +1,105 @@
package com.win.mq.utils.sfms;
import com.alibaba.fastjson.JSONObject;
import com.win.mq.config.SmfsConfigure;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.time.LocalDateTime;
import java.util.Collections;
@Slf4j
@Component
public class AccessTokenUtil {
private AccessTokenVO accessTokenVO;
@Autowired
private SmfsConfigure smfsConfigure;
@Autowired
private RestTemplate restTemplate;
public AccessTokenVO getAccessTokenVO() {
if(this.accessTokenVO == null) {
this.accessTokenVO = loginSfms();
}
LocalDateTime now = LocalDateTime.now();
if(now.isAfter(this.accessTokenVO.getExpiresTime())) {
this.accessTokenVO = this.refreshAccessToken();
}
return accessTokenVO;
}
/**
* 登录获取accessToken
* @return accessToken
*/
private AccessTokenVO loginSfms() {
HttpHeaders headers = new HttpHeaders();
headers.add("tenant-id", "1");
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.put("client_id", Collections.singletonList("win-sso-demo-by-password"));
map.put("client_secret", Collections.singletonList("test"));
map.put("grant_type", Collections.singletonList("password"));
map.put("username", Collections.singletonList(smfsConfigure.getUsername()));
map.put("password", Collections.singletonList(smfsConfigure.getPassword()));
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(map, headers);
// 发起POST请求
ResponseEntity<String> responseEntity = restTemplate.postForEntity(smfsConfigure.getAccessToken(), requestEntity, String.class);
// 获取返回结果
//if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {
// System.out.println("返回结果:" + responseEntity.getBody());
//} else {
// System.err.println("请求失败!");
//}
JSONObject object = JSONObject.parseObject(responseEntity.getBody());
if(object.getInteger("code") != 0) {
log.error(object.getString("msg"));
return null;
}
JSONObject accessTokenObject = JSONObject.parseObject(object.getString("data"));
AccessTokenVO accessTokenVO = new AccessTokenVO();
accessTokenVO.setAccessToken(accessTokenObject.getString("access_token"));
accessTokenVO.setRefreshToken(accessTokenObject.getString("refresh_token"));
accessTokenVO.setTokenType(accessTokenObject.getString("token_type"));
accessTokenVO.setExpiresIn(accessTokenObject.getLong("expires_in"));
accessTokenVO.setScope(accessTokenObject.getString("scope"));
LocalDateTime now = LocalDateTime.now();
now = now.plusNanos((accessTokenVO.getExpiresIn() - 1000) * 1_000_000); // 增加毫秒数并得到新的日期时间
accessTokenVO.setExpiresTime(now);
return accessTokenVO;
}
/**
* 登录获取accessToken
* @return accessToken
*/
private AccessTokenVO refreshAccessToken() {
HttpHeaders headers = new HttpHeaders();
headers.add("tenant-id", "1");
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.put("refreshToken", Collections.singletonList(this.accessTokenVO.getRefreshToken()));
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(map, headers);
// 发起POST请求
ResponseEntity<String> responseEntity = restTemplate.postForEntity(smfsConfigure.getRefreshToken(), requestEntity, String.class);
JSONObject object = JSONObject.parseObject(responseEntity.getBody());
if(object.getInteger("code") != 0) {
log.error(object.getString("msg"));
return this.getAccessTokenVO();
}
JSONObject refreshTokenObject = JSONObject.parseObject(object.getString("data"));
this.accessTokenVO.setAccessToken(refreshTokenObject.getString("access_token"));
this.accessTokenVO.setRefreshToken(refreshTokenObject.getString("refresh_token"));
LocalDateTime now = LocalDateTime.now();
now = now.plusNanos((accessTokenVO.getExpiresIn() - 1000) * 1_000_000); // 增加毫秒数并得到新的日期时间
this.accessTokenVO.setExpiresTime(now);
return this.accessTokenVO;
}
}

46
src/main/java/com/win/mq/utils/sfms/AccessTokenVO.java

@ -0,0 +1,46 @@
package com.win.mq.utils.sfms;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class AccessTokenVO {
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 令牌类型
*/
private String tokenType;
/**
* 过期时间,单位
*/
private Long expiresIn;
/**
* 授权范围,如果多个授权范围使用空格分隔
*/
private String scope;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}

33
src/main/java/com/win/mq/utils/sfms/RefreshTokenVO.java

@ -0,0 +1,33 @@
package com.win.mq.utils.sfms;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RefreshTokenVO {
/**
* 用户编号
*/
private Long userId;
/**
* 访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}

38
src/main/resources/application-dev.yml

@ -0,0 +1,38 @@
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 18080
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数,默认为100
accept-count: 100
threads:
# tomcat最大线程数,默认为200
max: 100
# Tomcat启动初始化的线程数,默认值10
min-spare: 10
rocketmq:
name-server: dev.ccwin-in.com:23887
producer:
group: wenyin
config:
dataPath: /opt/rocketmq-console/data #存储设置目录
sfms:
username: admin #用户名
password: 123456 #密码
purchase-order: http://localhost:12080/admin-api/wms/purchase-main/create #采购订单
access-token: http://localhost:12080/admin-api/system/oauth2/token #登陆token
refresh-token: http://localhost:12080/admin-api/system/auth/refresh-token #刷新token
logging:
file:
path: logs
level:
com.win: debug
org.springframework: warn

12
src/main/resources/application.yml

@ -0,0 +1,12 @@
spring:
application:
name: win
profiles:
active: dev
main:
allow-bean-definition-overriding: true
servlet:
multipart:
enabled: true
max-file-size: 200MB
max-request-size: 1000MB

108
src/main/resources/logback-spring.xml

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="logPath" source="logging.file.path" defaultValue="logs"/>
<!-- 日志存放路径 -->
<property name="log.path" value="${logPath}" />
<!--0. 日志格式和颜色渲染 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- 此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 系统日志输出 -->
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-info.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>INFO</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-error.log</file>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式 -->
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 过滤的级别 -->
<level>ERROR</level>
<!-- 匹配时的操作:接收(记录) -->
<onMatch>ACCEPT</onMatch>
<!-- 不匹配时的操作:拒绝(不记录) -->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 用户访问日志输出 -->
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path}/sys-user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志最大的历史 60天 -->
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${log.pattern}</pattern>
</encoder>
</appender>
<!-- 系统模块日志级别控制 -->
<logger name="com.hc" level="info" />
<!-- Spring日志级别控制 -->
<logger name="org.springframework" level="warn" />
<root level="error">
<appender-ref ref="console" />
</root>
<!--系统操作日志-->
<root level="info">
<appender-ref ref="file_info" />
<appender-ref ref="file_error" />
</root>
<!--系统用户操作日志-->
<logger name="sys-user" level="info">
<appender-ref ref="sys-user"/>
</logger>
</configuration>

13
src/test/java/com/win/mq/MqApplicationTests.java

@ -0,0 +1,13 @@
package com.win.mq;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MqApplicationTests {
@Test
void contextLoads() {
}
}
Loading…
Cancel
Save