Browse Source

init

master
nili 1 year ago
parent
commit
69b8e1727c
  1. 5
      .gitignore
  2. 9
      build
  3. 50
      game-dao/pom.xml
  4. 11
      game-dao/src/main/java/awesome/group/game/dao/bean/GameApp.java
  5. 8
      game-dao/src/main/java/awesome/group/game/dao/bean/User.java
  6. 21
      game-dao/src/main/java/awesome/group/game/dao/bean/WeGameUser.java
  7. 14
      game-dao/src/main/java/awesome/group/game/dao/bean/WxUserInfo.java
  8. 69
      game-dao/src/main/java/awesome/group/game/dao/config/BasicDataSourceConfig.java
  9. 22
      game-dao/src/main/java/awesome/group/game/dao/config/MybatisGeneralConfig.java
  10. 11
      game-dao/src/main/java/awesome/group/game/dao/mapper/GameAppMapper.java
  11. 7
      game-dao/src/main/java/awesome/group/game/dao/mapper/UserMapper.java
  12. 15
      game-dao/src/main/java/awesome/group/game/dao/mapper/WeGameUserMapper.java
  13. 69
      game-service/pom.xml
  14. 16
      game-service/src/main/java/awesome/group/game/service/UserService.java
  15. 85
      game-service/src/main/java/awesome/group/game/service/WxService.java
  16. 16
      game-service/src/main/java/awesome/group/game/service/bo/Code2SessionBo.java
  17. 6
      game-service/src/main/java/awesome/group/game/service/bo/WxResponse.java
  18. 19
      game-service/src/main/java/awesome/group/game/service/common/exception/PaganiException.java
  19. 8
      game-service/src/main/java/awesome/group/game/service/common/exception/PaganiExceptionCode.java
  20. 17
      game-service/src/main/java/awesome/group/game/service/common/log/Const.java
  21. 27
      game-service/src/main/java/awesome/group/game/service/common/log/IPLogConfig.java
  22. 22
      game-service/src/main/java/awesome/group/game/service/common/log/L.java
  23. 78
      game-service/src/main/java/awesome/group/game/service/common/log/PaganiLogger.java
  24. 6
      game-service/src/main/java/awesome/group/game/service/common/log/Status.java
  25. 49
      game-service/src/main/java/awesome/group/game/service/common/response/R.java
  26. 6
      game-service/src/main/java/awesome/group/game/service/constant/TokenConstants.java
  27. 31
      game-service/src/main/java/awesome/group/game/service/util/EncryptUtil.java
  28. 95
      game-service/src/main/java/awesome/group/game/service/util/HttpUtils.java
  29. 38
      game-service/src/main/java/awesome/group/game/service/util/JwtUtils.java
  30. 51
      game-web/pom.xml
  31. 18
      game-web/src/main/java/awesome/group/Application.java
  32. 47
      game-web/src/main/java/awesome/group/RequestContext.java
  33. 11
      game-web/src/main/java/awesome/group/aop/RestApi.java
  34. 77
      game-web/src/main/java/awesome/group/aop/RestApiAop.java
  35. 47
      game-web/src/main/java/awesome/group/controller/LoginController.java
  36. 26
      game-web/src/main/java/awesome/group/interceptor/InterceptorConfig.java
  37. 45
      game-web/src/main/java/awesome/group/interceptor/JwtInterceptor.java
  38. 41
      game-web/src/main/resources/application-default.yml
  39. 42
      game-web/src/main/resources/application-test.yml
  40. 4
      game-web/src/main/resources/logback-spring.xml
  41. 114
      game-web/src/main/resources/logconfig.xml
  42. 73
      pom.xml
  43. 20
      run
  44. 14
      stop

5
.gitignore

@ -0,0 +1,5 @@
/.idea/
/pid
**/target
/logs/
*.log

9
build

@ -0,0 +1,9 @@
#!/bin/bash
mvn clean package -U -DskipTests > /dev/null
if [ $? -eq 0 ]; then
echo "success"
else
echo "fail"
fi

50
game-dao/pom.xml

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>game</artifactId>
<groupId>awesome.group</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>game-dao</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<!--不用tomcat的数据库连接池-->
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>

11
game-dao/src/main/java/awesome/group/game/dao/bean/GameApp.java

@ -0,0 +1,11 @@
package awesome.group.game.dao.bean;
import lombok.Data;
import org.springframework.context.annotation.Bean;
@Data
public class GameApp {
private String name;
private String appId;
private String appSecret;
}

8
game-dao/src/main/java/awesome/group/game/dao/bean/User.java

@ -0,0 +1,8 @@
package awesome.group.game.dao.bean;
import lombok.Data;
@Data
public class User {
private Integer id;
}

21
game-dao/src/main/java/awesome/group/game/dao/bean/WeGameUser.java

@ -0,0 +1,21 @@
package awesome.group.game.dao.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class WeGameUser {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String appId;
private String openId;
private String nickname;
private Integer gender;
private String province;
private String city;
private String country;
private String avatarUrl;
private String unionId;
private String sessionKey;
}

14
game-dao/src/main/java/awesome/group/game/dao/bean/WxUserInfo.java

@ -0,0 +1,14 @@
package awesome.group.game.dao.bean;
import lombok.Data;
@Data
public class WxUserInfo {
public String avatarUrl;
public String nickName;
public Integer gender; //0: 未知;1:男性;2:女性
public String city;
public String province;
public String country;
public String language;
}

69
game-dao/src/main/java/awesome/group/game/dao/config/BasicDataSourceConfig.java

@ -0,0 +1,69 @@
package awesome.group.game.dao.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = BasicDataSourceConfig.BASE_PACKAGE,sqlSessionFactoryRef = BasicDataSourceConfig.SSF_NAME,sqlSessionTemplateRef = BasicDataSourceConfig.SST_NAME)
public class BasicDataSourceConfig {
public static final String DS_NAME = "basicDataSource";
public static final String TM_NAME = "basicTransactionManager";
public static final String SSF_NAME = "basicSqlSessionFactory";
public static final String SST_NAME = "basicSqlSessionTemplate";
public static final String DS_CFG_PREFIX = "datasource.game";
public static final String BASE_PACKAGE = "awesome.group.game.dao.mapper";
@Bean(name = DS_NAME)
@ConfigurationProperties(DS_CFG_PREFIX)
public DataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
@Primary
@Bean(name = TM_NAME)
public DataSourceTransactionManager transactionManager(@Qualifier(DS_NAME) DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = SSF_NAME)
public SqlSessionFactory sqlSessionFactory(@Qualifier(DS_NAME) DataSource dataSource,
@Qualifier(MybatisGeneralConfig.MBTS_CFG_NAME) MybatisConfiguration configuration) throws Exception {
MybatisSqlSessionFactoryBean factoryBean = new MybatisSqlSessionFactoryBean();
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
configuration.addInterceptor(interceptor);
factoryBean.setConfiguration(configuration);
factoryBean.setDataSource(dataSource);
return factoryBean.getObject();
}
@Bean(name = SST_NAME)
public SqlSessionTemplate sqlSessionTemplate(@Qualifier(SSF_NAME) SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

22
game-dao/src/main/java/awesome/group/game/dao/config/MybatisGeneralConfig.java

@ -0,0 +1,22 @@
package awesome.group.game.dao.config;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class MybatisGeneralConfig {
public static final String MBTS_CFG_NAME = "mybatisGeneralCfg";
@Bean(MBTS_CFG_NAME)
@ConfigurationProperties("mybatis-plus.configuration")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public MybatisConfiguration configuration() {
return new MybatisConfiguration();
}
}

11
game-dao/src/main/java/awesome/group/game/dao/mapper/GameAppMapper.java

@ -0,0 +1,11 @@
package awesome.group.game.dao.mapper;
import awesome.group.game.dao.bean.GameApp;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface GameAppMapper extends BaseMapper<GameApp> {
@Select("select * from game_app where app_id = #{appId}")
GameApp query(@Param("appId")String appId);
}

7
game-dao/src/main/java/awesome/group/game/dao/mapper/UserMapper.java

@ -0,0 +1,7 @@
package awesome.group.game.dao.mapper;
import awesome.group.game.dao.bean.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}

15
game-dao/src/main/java/awesome/group/game/dao/mapper/WeGameUserMapper.java

@ -0,0 +1,15 @@
package awesome.group.game.dao.mapper;
import awesome.group.game.dao.bean.WeGameUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface WeGameUserMapper extends BaseMapper<WeGameUser> {
@Select("select * from we_game_user where app_id = #{appId} and open_id = #{openId}")
WeGameUser query(@Param("appId")String appId, @Param("openId")String openId);
@Update("update we_game_user set session_key = #{sessionKey} where id = #{id}")
int updateSessionKey(@Param("sessionKey")String sessionKey, @Param("id")Integer id);
}

69
game-service/pom.xml

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>game</artifactId>
<groupId>awesome.group</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>game-service</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>awesome.group</groupId>
<artifactId>game-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>5.6.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.14.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
</dependencies>
</project>

16
game-service/src/main/java/awesome/group/game/service/UserService.java

@ -0,0 +1,16 @@
package awesome.group.game.service;
import awesome.group.game.dao.bean.User;
import awesome.group.game.dao.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
public User getUser(Integer uid) {
return userMapper.selectById(uid);
}
}

85
game-service/src/main/java/awesome/group/game/service/WxService.java

@ -0,0 +1,85 @@
package awesome.group.game.service;
import awesome.group.game.dao.bean.GameApp;
import awesome.group.game.dao.bean.WeGameUser;
import awesome.group.game.dao.bean.WxUserInfo;
import awesome.group.game.dao.mapper.GameAppMapper;
import awesome.group.game.dao.mapper.WeGameUserMapper;
import awesome.group.game.service.bo.Code2SessionBo;
import awesome.group.game.service.common.exception.PaganiException;
import awesome.group.game.service.common.exception.PaganiExceptionCode;
import awesome.group.game.service.util.EncryptUtil;
import awesome.group.game.service.util.HttpUtils;
import awesome.group.game.service.util.JwtUtils;
import com.google.gson.Gson;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Service
public class WxService {
@Resource
private WeGameUserMapper weGameUserMapper;
@Resource
private GameAppMapper gameAppMapper;
public String login(String code, String appId) {
Code2SessionBo data = getSession(code, appId);
if (data == null || data.openid == null) {
throw new PaganiException(PaganiExceptionCode.GENERAL_ERROR, "登陆失败,非法code");
}
WeGameUser u = weGameUserMapper.query(appId, data.openid);
if (u == null) {
u = new WeGameUser();
u.setOpenId(data.openid);
u.setAppId(appId);
u.setUnionId(data.unionid);
u.setSessionKey(data.session_key);
weGameUserMapper.insert(u);
} else {
weGameUserMapper.updateSessionKey(data.session_key, u.getId());
}
return JwtUtils.generatorToken(u.getId() + "", 2 * 86400);
}
public void updateUserInfo(Integer userId, String rawData, String signature) {
if (!verify(userId, rawData, signature)) {
throw new PaganiException(PaganiExceptionCode.GENERAL_ERROR, "签名有误");
}
Gson gson = new Gson();
WxUserInfo info = gson.fromJson(rawData, WxUserInfo.class);
WeGameUser u = new WeGameUser();
BeanUtils.copyProperties(info, u);
u.setId(userId);
u.setNickname(info.nickName);
u.setAvatarUrl(info.avatarUrl);
weGameUserMapper.updateById(u);
}
public boolean verify(Integer userId, String rawData, String signature) {
WeGameUser u = weGameUserMapper.selectById(userId);
if (!StringUtils.hasText(u.getSessionKey())) {
return false;
}
String str = rawData + u.getSessionKey();
return signature.equals(EncryptUtil.sha1(str));
}
public Code2SessionBo getSession(String code, String appId) {
GameApp gameApp = gameAppMapper.query(appId);
String api = "https://api.weixin.qq.com/sns/jscode2session";
Map<String, String> param = new HashMap<>();
param.put("appid", gameApp.getAppId());
param.put("secret", gameApp.getAppSecret());
param.put("js_code", code);
param.put("grant_type", "authorization_code");
return HttpUtils.get(api, param, null, Code2SessionBo.class);
}
}

16
game-service/src/main/java/awesome/group/game/service/bo/Code2SessionBo.java

@ -0,0 +1,16 @@
package awesome.group.game.service.bo;
public class Code2SessionBo extends WxResponse{
public String session_key;
public String openid;
public String unionid;
public Code2SessionBo() {
}
public Code2SessionBo(String session_key, String openid, String unionid) {
this.session_key = session_key;
this.openid = openid;
this.unionid = unionid;
}
}

6
game-service/src/main/java/awesome/group/game/service/bo/WxResponse.java

@ -0,0 +1,6 @@
package awesome.group.game.service.bo;
public class WxResponse {
public Integer errcode;
public String errmsg;
}

19
game-service/src/main/java/awesome/group/game/service/common/exception/PaganiException.java

@ -0,0 +1,19 @@
package awesome.group.game.service.common.exception;
public class PaganiException extends RuntimeException {
private int code;
public PaganiException(int code, String msg, Throwable t) {
super(msg, t);
this.code = code;
}
public PaganiException(int code, String msg) {
super(msg);
this.code = code;
}
public int getCode() {
return code;
}
}

8
game-service/src/main/java/awesome/group/game/service/common/exception/PaganiExceptionCode.java

@ -0,0 +1,8 @@
package awesome.group.game.service.common.exception;
public class PaganiExceptionCode {
public static final int LOG_ERROR = -10001;
public static final int GENERAL_ERROR = -99999;
public static final int ILLEGAL_REQUEST = 10001;
}

17
game-service/src/main/java/awesome/group/game/service/common/log/Const.java

@ -0,0 +1,17 @@
package awesome.group.game.service.common.log;
public class Const {
public static final String LOGGER_API = "log.api";
public static final String LOGGER_TRACE = "log.trace";
public static final String COST = "key_cost";
public static final String ACTION = "key_action";
public static final String STATUS = "key_status";
public static final String JWT = "key_jwt";
public static final String METHOD_NAME = "key_method_name";
public static final String API_LOG_FORMAT = "{%s,%s,%s}";
public static final String STRING_DEFAULT = "null";
}

27
game-service/src/main/java/awesome/group/game/service/common/log/IPLogConfig.java

@ -0,0 +1,27 @@
package awesome.group.game.service.common.log;
import awesome.group.game.service.common.exception.PaganiException;
import awesome.group.game.service.common.exception.PaganiExceptionCode;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import java.net.InetAddress;
public class IPLogConfig extends ClassicConverter {
private static String msIp = null;
static {
try {
msIp = InetAddress.getLocalHost().getHostAddress();
} catch (Exception e) {
throw new PaganiException(PaganiExceptionCode.LOG_ERROR, "get local ip failed", e);
}
}
@Override
public String convert(ILoggingEvent event) {
return msIp;
}
}

22
game-service/src/main/java/awesome/group/game/service/common/log/L.java

@ -0,0 +1,22 @@
package awesome.group.game.service.common.log;
public class L {
private static PaganiLogger msLogger = new PaganiLogger();
public static void api(int cost, Status status, String methodName, String jwtToken, String cookie, String param, String resp) {
msLogger.api(cost, status, methodName, jwtToken, cookie, param, resp);
}
public static void api(int cost, Status status, String methodName, String jwtToken, String cookie, String param, String resp, Throwable t) {
msLogger.api(cost, status, methodName, jwtToken, cookie, param, resp, t);
}
public static void trace(String action, String msg) {
msLogger.trace(action, msg);
}
public static void trace(String action, String msg, Throwable t) {
msLogger.trace(action, msg, t);
}
}

78
game-service/src/main/java/awesome/group/game/service/common/log/PaganiLogger.java

@ -0,0 +1,78 @@
package awesome.group.game.service.common.log;
import awesome.group.game.service.common.exception.PaganiException;
import awesome.group.game.service.common.exception.PaganiExceptionCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class PaganiLogger {
private Map<String, Logger> mLoggers = new ConcurrentHashMap<String, Logger>();
public void api(int cost, Status status, String methodName, String accessToken, String cookie, String param, String resp) {
checkCostStatus(cost, status);
String msg = String.format(Const.API_LOG_FORMAT, param, resp, cookie);
Logger logger = getLogger(Const.LOGGER_API);
MDC.put(Const.COST, String.valueOf(cost));
MDC.put(Const.STATUS, String.valueOf(status.ordinal()));
MDC.put(Const.JWT, accessToken);
MDC.put(Const.METHOD_NAME, methodName);
logger.info(msg);
mdcClear(Const.COST, Const.STATUS, Const.JWT, Const.METHOD_NAME);
}
public void api(int cost, Status status, String methodName, String accessToken, String cookie, String param, String resp, Throwable t) {
checkCostStatus(cost, status);
String msg = String.format(Const.API_LOG_FORMAT, param, resp, cookie);
Logger logger = getLogger(Const.LOGGER_API);
MDC.put(Const.COST, String.valueOf(cost));
MDC.put(Const.STATUS, String.valueOf(status.ordinal()));
MDC.put(Const.JWT, accessToken);
MDC.put(Const.METHOD_NAME, methodName);
logger.error(msg, t);
mdcClear(Const.COST, Const.STATUS, Const.JWT, Const.METHOD_NAME);
}
public void trace(String action, String msg) {
Logger logger = getLogger(Const.LOGGER_TRACE);
MDC.put(Const.ACTION, action);
logger.info(msg);
mdcClear(Const.ACTION);
}
public void trace(String action, String msg, Throwable t) {
Logger logger = getLogger(Const.LOGGER_TRACE);
MDC.put(Const.ACTION, action);
logger.error(msg, t);
mdcClear(Const.ACTION);
}
private void checkCostStatus(long cost, Status status) {
if (null == status || cost < 0) {
throw new PaganiException(PaganiExceptionCode.LOG_ERROR,
String.format("statistics param error cost = %d, status = %s",
cost, null == status ? "" : status.toString()));
}
}
private void mdcClear(String... args) {
for (String key : args) {
MDC.remove(key);
}
}
private Logger getLogger(String key) {
if (null == key) {
throw new PaganiException(PaganiExceptionCode.LOG_ERROR, "getLogger = null");
}
Logger logger = mLoggers.get(key);
if (null == logger) {
logger = LoggerFactory.getLogger(key);
mLoggers.put(key, logger);
}
return logger;
}
}

6
game-service/src/main/java/awesome/group/game/service/common/log/Status.java

@ -0,0 +1,6 @@
package awesome.group.game.service.common.log;
public enum Status {
FAILED,
SUCCESS
}

49
game-service/src/main/java/awesome/group/game/service/common/response/R.java

@ -0,0 +1,49 @@
package awesome.group.game.service.common.response;
public class R<T> {
public static final int CODE_SUCCESS = 0;
private Integer code;
private String message = "";
private T data;
public R() {
}
public R(T result) {
this.data = result;
this.code = CODE_SUCCESS;
this.message = "ok";
}
public R(Integer code, String message, T result) {
this.code = code;
this.message = message;
this.data = result;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

6
game-service/src/main/java/awesome/group/game/service/constant/TokenConstants.java

@ -0,0 +1,6 @@
package awesome.group.game.service.constant;
public class TokenConstants {
public static final String ACCESS_TOKEN_TYPE = "accessToken";
public static final String REFRESH_TOKEN_TYPE = "refreshToken";
}

31
game-service/src/main/java/awesome/group/game/service/util/EncryptUtil.java

@ -0,0 +1,31 @@
package awesome.group.game.service.util;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
public class EncryptUtil {
public static String sha1(String text) {
String sha1 = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(text.getBytes(StandardCharsets.UTF_8));
sha1 = byteToHex(crypt.digest());
} catch (NoSuchAlgorithmException e) {
//忽略
}
return sha1;
}
public static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
}

95
game-service/src/main/java/awesome/group/game/service/util/HttpUtils.java

@ -0,0 +1,95 @@
package awesome.group.game.service.util;
import awesome.group.game.service.bo.WxResponse;
import awesome.group.game.service.common.exception.PaganiException;
import awesome.group.game.service.common.exception.PaganiExceptionCode;
import awesome.group.game.service.common.log.L;
import com.google.gson.Gson;
import okhttp3.*;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class HttpUtils {
private static final OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(2, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(8, 5, TimeUnit.MINUTES)).build();
private static Gson gson = new Gson();
private static final int WX_RESP_CODE_SUCCESS = 0;
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
public static <T> T postForm(String url, Map<String, String> query, Map<String, String> form,
Map<String, String> headers, Class<T> dataType) {
FormBody.Builder bodyBuilder = new FormBody.Builder();
for (Map.Entry<String, String> kv : form.entrySet()) {
bodyBuilder.add(kv.getKey(), kv.getValue());
}
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
for (Map.Entry<String, String> kv : query.entrySet()) {
urlBuilder.addQueryParameter(kv.getKey(), kv.getValue());
}
Request.Builder requestBuilder = new Request.Builder().post(bodyBuilder.build()).url(urlBuilder.build());
if (!CollectionUtils.isEmpty(headers)) {
headers.entrySet().stream().forEach(x -> {
requestBuilder.addHeader(x.getKey(), x.getValue());
});
}
Request request = requestBuilder.build();
String msg = "url:" + url + ",header:" + gson.toJson(headers) + ", body:" + form + ", query:" + query;
return doHttpExecute(msg, request, dataType);
}
public static <T> T postJson(String url, Object body, Map<String, String> headers, Class<T> dataType) {
String bodyStr = gson.toJson(body);
RequestBody requestBody = RequestBody.create(JSON, bodyStr);
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
Request.Builder requestBuilder = new Request.Builder().post(requestBody).url(urlBuilder.build());
if (!CollectionUtils.isEmpty(headers)) {
headers.forEach(requestBuilder::addHeader);
}
Request request = requestBuilder.build();
String msg = "url:" + url + ",header:" + gson.toJson(headers) + ", body:" + bodyStr;
return doHttpExecute(msg, request, dataType);
}
public static <T> T get(String url, Map<String, String> queryStr, Map<String, String> headers, Class<T> dataType) {
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
for (Map.Entry<String, String> kv : queryStr.entrySet()) {
urlBuilder.addQueryParameter(kv.getKey(), kv.getValue());
}
Request.Builder requestBuilder = new Request.Builder().get().url(urlBuilder.build());
if (!CollectionUtils.isEmpty(headers)) {
headers.forEach(requestBuilder::addHeader);
}
Request request = requestBuilder.build();
String msg = "url:" + url + ",header:" + gson.toJson(headers) + ", query:" + gson.toJson(queryStr);
return doHttpExecute(msg, request, dataType);
}
private static <T> T doHttpExecute(String msg, Request request, Class<T> dataType) {
try {
long now = System.currentTimeMillis();
Response resp = httpClient.newCall(request).execute();
if (!resp.isSuccessful() || resp.body() == null) {
L.trace("http_request_error", msg + ",http_code:" + resp.code());
throw new PaganiException(PaganiExceptionCode.GENERAL_ERROR, "http_request_error");
}
String res = resp.body().string();
return gson.fromJson(res, dataType);
} catch (IOException ioe) {
L.trace("http_request_error", msg + ",msg:" + ioe.getMessage(), ioe);
throw new PaganiException(PaganiExceptionCode.GENERAL_ERROR, ioe.getMessage(), ioe);
}
}
}

38
game-service/src/main/java/awesome/group/game/service/util/JwtUtils.java

@ -0,0 +1,38 @@
package awesome.group.game.service.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
public class JwtUtils {
//盐
private static final String SIGN = "CPFmsb!@#$$";
private static final String JWT_KEY_USERID = "userId";
public static String generatorToken(String userId, long expireSeconds) {
LocalDateTime localDateTimeNow = LocalDateTime.now();
LocalDateTime localDateTimeExpire = localDateTimeNow.plusSeconds(expireSeconds);
Date expire = Date.from(localDateTimeExpire.atZone(ZoneId.systemDefault()).toInstant());
JWTCreator.Builder builder = JWT.create();
builder.withExpiresAt(expire);
builder.withClaim(JWT_KEY_USERID, userId);
//生成token
return builder.sign(Algorithm.HMAC256(SIGN));
}
//解析token
public static Integer parseToken(String token) {
DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
String userId = verify.getClaim(JWT_KEY_USERID).asString();
return Integer.parseInt(userId);
}
}

51
game-web/pom.xml

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>game</artifactId>
<groupId>awesome.group</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>game-web</artifactId>
<dependencies>
<dependency>
<groupId>awesome.group</groupId>
<artifactId>game-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>awesome.group</groupId>
<artifactId>game-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

18
game-web/src/main/java/awesome/group/Application.java

@ -0,0 +1,18 @@
package awesome.group;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.ApplicationPidFileWriter;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@SpringBootApplication
@ServletComponentScan
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class Application {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter());
application.run(args);
}
}

47
game-web/src/main/java/awesome/group/RequestContext.java

@ -0,0 +1,47 @@
package awesome.group;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
public class RequestContext {
private static final String KEY_REQUEST = "request";
private static final String KEY_RESPONSE = "response";
private static final String KEY_UID = "uid";
private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new ThreadLocal<>();
public static void init(HttpServletRequest request, HttpServletResponse response, Integer userId) {
Map<String, Object> context = new HashMap<>();
context.put(KEY_REQUEST, request);
context.put(KEY_RESPONSE, response);
context.put(KEY_UID, userId);
THREAD_LOCAL.set(context);
}
public static HttpServletRequest getRequest() {
return (HttpServletRequest) THREAD_LOCAL.get().get(KEY_REQUEST);
}
public static HttpServletResponse getResponse() {
return (HttpServletResponse) THREAD_LOCAL.get().get(KEY_RESPONSE);
}
public static Integer getUid() {
if (THREAD_LOCAL.get() == null) {
return null;
}
return (Integer) THREAD_LOCAL.get().get(KEY_UID);
}
}

11
game-web/src/main/java/awesome/group/aop/RestApi.java

@ -0,0 +1,11 @@
package awesome.group.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RestApi {
}

77
game-web/src/main/java/awesome/group/aop/RestApiAop.java

@ -0,0 +1,77 @@
package awesome.group.aop;
import awesome.group.RequestContext;
import awesome.group.game.service.common.exception.PaganiException;
import awesome.group.game.service.common.exception.PaganiExceptionCode;
import awesome.group.game.service.common.log.L;
import awesome.group.game.service.common.log.Status;
import awesome.group.game.service.common.response.R;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Component
@Order(1)
public class RestApiAop {
@Autowired
private ObjectMapper objectMapper;
@Around("@annotation(RestApi)")
public Object advice(ProceedingJoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String methodName = signature.getMethod().getName();
Throwable exception = null;
long start = System.currentTimeMillis();
Object[] params = joinPoint.getArgs();
Object ret = null;
Status status = Status.SUCCESS;
try {
ret = joinPoint.proceed();
} catch (Throwable e) {
exception = e;
if (e instanceof PaganiException) {
ret = new R<>(((PaganiException) e).getCode(), e.getMessage(), null);
} else {
status = Status.FAILED;
ret = new R<>(PaganiExceptionCode.GENERAL_ERROR, "服务器错误,请稍后重试", null);
}
} finally {
int cost = (int) (System.currentTimeMillis() - start);
String paramStr = "";
if (params != null) {
try {
paramStr = objectMapper.writeValueAsString(params);
} catch (JsonProcessingException e) {
}
}
String retStr = "";
if (ret != null) {
try {
retStr = objectMapper.writeValueAsString(ret);
} catch (JsonProcessingException e) {
}
}
String uid = RequestContext.getUid() + "";
//TODO cookie看情况取不取
String cookie = "";
if (exception == null) {
L.api(cost, status, methodName, uid, cookie, paramStr, retStr);
} else {
L.api(cost, status, methodName, uid, cookie, paramStr, retStr, exception);
}
}
return ret;
}
}

47
game-web/src/main/java/awesome/group/controller/LoginController.java

@ -0,0 +1,47 @@
package awesome.group.controller;
import awesome.group.RequestContext;
import awesome.group.aop.RestApi;
import awesome.group.game.service.WxService;
import awesome.group.game.service.common.response.R;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/game/auth")
public class LoginController {
@Resource
private WxService wxService;
/**
* 微信登陆
* 返回jwt token
*
* @param code 微信wx.login获取到的code
*/
@PostMapping("/login")
@RestApi
public R<String> wxLogin(@RequestParam String code, @RequestParam String appId) {
return new R<>(R.CODE_SUCCESS, "", wxService.login(code, appId));
}
/**
* 更新用户信息
* 必须先登陆需在login调用30分钟内
*
* @param rawData 微信wx.getUserInfo获取到到rawData
* @param signature 微信wx.getUserInfo获取到到signature
*/
@PostMapping("/updateUserInfo")
@RestApi
public R<Void> updateUserInfo(@RequestParam String rawData, @RequestParam String signature) {
Integer userId = RequestContext.getUid();
wxService.updateUserInfo(userId, rawData, signature);
return new R<>(R.CODE_SUCCESS, "", null);
}
}

26
game-web/src/main/java/awesome/group/interceptor/InterceptorConfig.java

@ -0,0 +1,26 @@
package awesome.group.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration //配置类
public class InterceptorConfig implements WebMvcConfigurer {
@Bean //手动注入 JwtInterceptor 对象
public JwtInterceptor jwtInterceptor() {
return new JwtInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor())
//拦截的路径
.addPathPatterns("/**")
//不拦截的路径
.excludePathPatterns("/api/game/auth/login")
.excludePathPatterns("/api/game/user/demo");
}
}

45
game-web/src/main/java/awesome/group/interceptor/JwtInterceptor.java

@ -0,0 +1,45 @@
package awesome.group.interceptor;
import awesome.group.RequestContext;
import awesome.group.game.service.common.log.L;
import awesome.group.game.service.common.response.R;
import awesome.group.game.service.util.JwtUtils;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.google.gson.Gson;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import java.io.PrintWriter;
import java.util.List;
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
List<String> openApi = List.of("/api/game/user/demo");
try {
if (StringUtils.hasText(token)) {
Integer userId = JwtUtils.parseToken(token);
RequestContext.init(request, response, userId);
return true;
}
} catch (TokenExpiredException e) {
//忽略
} catch (Exception e) {
L.trace("parseTokenError", "token:" + token, e);
}
String path = request.getRequestURI().substring(request.getContextPath().length()).replaceAll("[/]+$", "");
for (String s : openApi) {
if (path.startsWith(s)) {
return true;
}
}
PrintWriter out = response.getWriter();
Gson gson = new Gson();
out.print(gson.toJson(new R<>(-88888, "not log in", null)));
return false;
}
}

41
game-web/src/main/resources/application-default.yml

@ -0,0 +1,41 @@
spring:
application:
name: game
config:
activate:
on-profile: default
aop:
auto: true
proxy-target-class: true
pid:
file: pid #pid文件名
datasource:
game:
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://localhost:3306/game?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&connectTimeout=300&socketTimeout=2000&serverTimezone=Hongkong&zeroDateTimeBehavior=convertToNull
username: root
password:
connectionTimeout: 300
maximumPoolSize: 5
minimumIdle: 1
idleTimeout: 600000 #This property controls the maximum amount of time that a connection is allowed to sit idle in the pool
maxLifetime: 3600000 #This property controls the maximum lifetime of a connection in the pool
mybatis-plus:
configuration:
map-underscore-to-camel-case: true #数据库字段下划线映射java对象属性用驼峰命名
server:
port: 9001
tomcat:
connection-timeout: 60000 #Time in milliseconds that connectors will wait for another HTTP request before closing the connection.
accept-count: 100 # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
max-connections: 256 # Maximum number of connections that the server will accept and process at any given time.
max-http-form-post-size: 20MB
threads:
max: 16
min-spare: 4
servlet:
encoding:
enabled: true
charset: utf-8

42
game-web/src/main/resources/application-test.yml

@ -0,0 +1,42 @@
spring:
application:
name: game
config:
activate:
on-profile: test
aop:
auto: true
proxy-target-class: true
pid:
file: pid #pid文件名
datasource:
game:
type: com.zaxxer.hikari.HikariDataSource
jdbcUrl: jdbc:mysql://localhost:3306/game?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&connectTimeout=300&socketTimeout=2000&serverTimezone=Hongkong&zeroDateTimeBehavior=convertToNull
username: game
password: Vd12luSjmwAXuwDH
connectionTimeout: 300
maximumPoolSize: 5
minimumIdle: 1
idleTimeout: 600000 #This property controls the maximum amount of time that a connection is allowed to sit idle in the pool
maxLifetime: 3600000 #This property controls the maximum lifetime of a connection in the pool
mybatis-plus:
configuration:
map-underscore-to-camel-case: true #数据库字段下划线映射java对象属性用驼峰命名
server:
port: 8000
tomcat:
connection-timeout: 60000 #Time in milliseconds that connectors will wait for another HTTP request before closing the connection.
accept-count: 100 # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
max-connections: 256 # Maximum number of connections that the server will accept and process at any given time.
threads:
max: 16
min-spare: 4
servlet:
encoding:
enabled: true
charset: utf-8

4
game-web/src/main/resources/logback-spring.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="logconfig.xml"/>
</configuration>

114
game-web/src/main/resources/logconfig.xml

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<included>
<property name="LOG_HOME" value="logs"/>
<conversionRule conversionWord="hostIp" converterClass="awesome.group.game.service.common.log.IPLogConfig"/>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<property name="ENCODER_PATTERN"
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%logger{5}] - %msg%n"/>
<!-- 文件日志:输出全部日志到文件 -->
<appender name="OUTPUT_FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${LOG_HOME}/biz.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/biz.log.%d{yyyyMMddHH}</fileNamePattern>
<maxHistory>72</maxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${ENCODER_PATTERN}</pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC_OUTPUT_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="OUTPUT_FILE"/>
</appender>
<!--trace log pattern-->
<property name="TRACE_ENCODER_PATTERN"
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%X{key_action:-}] - %msg%n"/>
<!--trace log 输出文件-->
<appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/trace.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/trace.log.%d{yyyyMMddHH}</fileNamePattern>
<maxHistory>72</maxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>${TRACE_ENCODER_PATTERN}</Pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC_TRACE_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="TRACE_FILE"/>
</appender>
<!-- api日志-->
<property name="API_ENCODER_PATTERN"
value="[%level][%d{yyyy-MM-dd HH:mm:ss}][%t][${springAppName:-}][%X{key_method_name:-}][%X{X-B3-TraceId:-}][%X{X-B3-SpanId:-}][%X{X-B3-ParentSpanId:-}][%hostIp][%X{key_cost:-}][%X{key_status:-}][%X{key_jwt:-}] - %msg%n"/>
<appender name="API_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/api.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/api.log.%d{yyyyMMddHH}</fileNamePattern>
<maxHistory>24</maxHistory>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<Pattern>${API_ENCODER_PATTERN}</Pattern>
</encoder>
</appender>
<!-- 异步输出 -->
<appender name="ASYNC_API_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>64</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="API_FILE"/>
</appender>
<!-- api日志-->
<logger name="log.trace" level="INFO" additivity="false">
<appender-ref ref="ASYNC_TRACE_FILE"/>
</logger>
<logger name="log.api" level="INFO" additivity="false">
<appender-ref ref="ASYNC_API_FILE"/>
</logger>
<logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
<logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
<logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
<logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
<logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
<logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
<logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
<root additivity="false">
<level value="INFO"/>
<appender-ref ref="ASYNC_OUTPUT_FILE"/>
</root>
</included>

73
pom.xml

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>awesome.group</groupId>
<artifactId>game</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>game-dao</module>
<module>game-service</module>
<module>game-web</module>
</modules>
<packaging>pom</packaging>
<properties>
<java.version>17</java.version>
<awesome.group.common.version>1.0-SNAPSHOT</awesome.group.common.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- mybatis-plus 3.5.3 才支持 spring boot 3-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.11.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<!--源码打包-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase><!--指定绑定的声明周期阶段-->
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

20
run

@ -0,0 +1,20 @@
#!/bin/bash
project=`cat env.conf | awk -F , '{print$1}'`
profile=`cat env.conf | awk -F , '{print$2}'`
logdir=logs
if [ ! -d "$logdir" ];then
mkdir $logdir
fi
targetdir=$project/target
jar=$project-1.0-SNAPSHOT.jar
rm -rf jar
mkdir jar
cp $targetdir/$jar jar/
java -server -Xmx1G -Xms1G -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:+UseCompressedOops -XX:+UseCompressedClassPointers -verbose:gc -Xlog:gc*:logs/gc.log:time,l,tg:filecount=7,filesize=16M -jar jar/$jar --spring.profiles.active=$profile > run.log 2>&1 & echo $! > pid

14
stop

@ -0,0 +1,14 @@
#!/bin/bash
# ======== 下面是原来的下线逻辑 ===========
if [ -f pid ]; then
if kill `cat pid` ; then
echo 'kill process succeed'
else
echo 'kill process fail'
exit 1
fi
else
echo 'pid file not exists'
exit 1
fi
Loading…
Cancel
Save