From 69b8e1727cd9e24125e470a37fa179067ac95b50 Mon Sep 17 00:00:00 2001 From: nili Date: Tue, 22 Aug 2023 23:43:03 +0800 Subject: [PATCH] init --- .gitignore | 5 + build | 9 ++ game-dao/pom.xml | 50 ++++++++ .../awesome/group/game/dao/bean/GameApp.java | 11 ++ .../awesome/group/game/dao/bean/User.java | 8 ++ .../group/game/dao/bean/WeGameUser.java | 21 ++++ .../group/game/dao/bean/WxUserInfo.java | 14 +++ .../dao/config/BasicDataSourceConfig.java | 69 +++++++++++ .../game/dao/config/MybatisGeneralConfig.java | 22 ++++ .../group/game/dao/mapper/GameAppMapper.java | 11 ++ .../group/game/dao/mapper/UserMapper.java | 7 ++ .../game/dao/mapper/WeGameUserMapper.java | 15 +++ game-service/pom.xml | 69 +++++++++++ .../group/game/service/UserService.java | 16 +++ .../awesome/group/game/service/WxService.java | 85 +++++++++++++ .../group/game/service/bo/Code2SessionBo.java | 16 +++ .../group/game/service/bo/WxResponse.java | 6 + .../common/exception/PaganiException.java | 19 +++ .../common/exception/PaganiExceptionCode.java | 8 ++ .../group/game/service/common/log/Const.java | 17 +++ .../game/service/common/log/IPLogConfig.java | 27 +++++ .../group/game/service/common/log/L.java | 22 ++++ .../game/service/common/log/PaganiLogger.java | 78 ++++++++++++ .../group/game/service/common/log/Status.java | 6 + .../group/game/service/common/response/R.java | 49 ++++++++ .../game/service/constant/TokenConstants.java | 6 + .../group/game/service/util/EncryptUtil.java | 31 +++++ .../group/game/service/util/HttpUtils.java | 95 +++++++++++++++ .../group/game/service/util/JwtUtils.java | 38 ++++++ game-web/pom.xml | 51 ++++++++ .../main/java/awesome/group/Application.java | 18 +++ .../java/awesome/group/RequestContext.java | 47 ++++++++ .../main/java/awesome/group/aop/RestApi.java | 11 ++ .../java/awesome/group/aop/RestApiAop.java | 77 ++++++++++++ .../group/controller/LoginController.java | 47 ++++++++ .../group/interceptor/InterceptorConfig.java | 26 ++++ .../group/interceptor/JwtInterceptor.java | 45 +++++++ .../main/resources/application-default.yml | 41 +++++++ .../src/main/resources/application-test.yml | 42 +++++++ .../src/main/resources/logback-spring.xml | 4 + game-web/src/main/resources/logconfig.xml | 114 ++++++++++++++++++ pom.xml | 73 +++++++++++ run | 20 +++ stop | 14 +++ 44 files changed, 1460 insertions(+) create mode 100644 .gitignore create mode 100755 build create mode 100644 game-dao/pom.xml create mode 100644 game-dao/src/main/java/awesome/group/game/dao/bean/GameApp.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/bean/User.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/bean/WeGameUser.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/bean/WxUserInfo.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/config/BasicDataSourceConfig.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/config/MybatisGeneralConfig.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/mapper/GameAppMapper.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/mapper/UserMapper.java create mode 100644 game-dao/src/main/java/awesome/group/game/dao/mapper/WeGameUserMapper.java create mode 100644 game-service/pom.xml create mode 100644 game-service/src/main/java/awesome/group/game/service/UserService.java create mode 100644 game-service/src/main/java/awesome/group/game/service/WxService.java create mode 100644 game-service/src/main/java/awesome/group/game/service/bo/Code2SessionBo.java create mode 100644 game-service/src/main/java/awesome/group/game/service/bo/WxResponse.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/exception/PaganiException.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/exception/PaganiExceptionCode.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/log/Const.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/log/IPLogConfig.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/log/L.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/log/PaganiLogger.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/log/Status.java create mode 100644 game-service/src/main/java/awesome/group/game/service/common/response/R.java create mode 100644 game-service/src/main/java/awesome/group/game/service/constant/TokenConstants.java create mode 100644 game-service/src/main/java/awesome/group/game/service/util/EncryptUtil.java create mode 100644 game-service/src/main/java/awesome/group/game/service/util/HttpUtils.java create mode 100644 game-service/src/main/java/awesome/group/game/service/util/JwtUtils.java create mode 100644 game-web/pom.xml create mode 100644 game-web/src/main/java/awesome/group/Application.java create mode 100644 game-web/src/main/java/awesome/group/RequestContext.java create mode 100644 game-web/src/main/java/awesome/group/aop/RestApi.java create mode 100644 game-web/src/main/java/awesome/group/aop/RestApiAop.java create mode 100644 game-web/src/main/java/awesome/group/controller/LoginController.java create mode 100644 game-web/src/main/java/awesome/group/interceptor/InterceptorConfig.java create mode 100644 game-web/src/main/java/awesome/group/interceptor/JwtInterceptor.java create mode 100644 game-web/src/main/resources/application-default.yml create mode 100644 game-web/src/main/resources/application-test.yml create mode 100644 game-web/src/main/resources/logback-spring.xml create mode 100644 game-web/src/main/resources/logconfig.xml create mode 100644 pom.xml create mode 100755 run create mode 100755 stop diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..934919e --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.idea/ +/pid +**/target +/logs/ +*.log \ No newline at end of file diff --git a/build b/build new file mode 100755 index 0000000..b207c4b --- /dev/null +++ b/build @@ -0,0 +1,9 @@ +#!/bin/bash +mvn clean package -U -DskipTests > /dev/null + +if [ $? -eq 0 ]; then + echo "success" +else + echo "fail" +fi + diff --git a/game-dao/pom.xml b/game-dao/pom.xml new file mode 100644 index 0000000..a2227bf --- /dev/null +++ b/game-dao/pom.xml @@ -0,0 +1,50 @@ + + + + game + awesome.group + 1.0-SNAPSHOT + + 4.0.0 + + game-dao + + + 17 + 17 + UTF-8 + + + + + com.baomidou + mybatis-plus-boot-starter + + + mysql + mysql-connector-java + + + org.springframework.boot + spring-boot-starter-jdbc + + + + org.apache.tomcat + tomcat-jdbc + + + + + org.springframework.boot + spring-boot-starter-validation + + + org.projectlombok + lombok + + + + \ No newline at end of file diff --git a/game-dao/src/main/java/awesome/group/game/dao/bean/GameApp.java b/game-dao/src/main/java/awesome/group/game/dao/bean/GameApp.java new file mode 100644 index 0000000..5446449 --- /dev/null +++ b/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; +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/bean/User.java b/game-dao/src/main/java/awesome/group/game/dao/bean/User.java new file mode 100644 index 0000000..f1ae3c3 --- /dev/null +++ b/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; +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/bean/WeGameUser.java b/game-dao/src/main/java/awesome/group/game/dao/bean/WeGameUser.java new file mode 100644 index 0000000..7b34c03 --- /dev/null +++ b/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; +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/bean/WxUserInfo.java b/game-dao/src/main/java/awesome/group/game/dao/bean/WxUserInfo.java new file mode 100644 index 0000000..cbf150a --- /dev/null +++ b/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; +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/config/BasicDataSourceConfig.java b/game-dao/src/main/java/awesome/group/game/dao/config/BasicDataSourceConfig.java new file mode 100644 index 0000000..63fdf4e --- /dev/null +++ b/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); + } +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/config/MybatisGeneralConfig.java b/game-dao/src/main/java/awesome/group/game/dao/config/MybatisGeneralConfig.java new file mode 100644 index 0000000..ac5e351 --- /dev/null +++ b/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(); + } + +} \ No newline at end of file diff --git a/game-dao/src/main/java/awesome/group/game/dao/mapper/GameAppMapper.java b/game-dao/src/main/java/awesome/group/game/dao/mapper/GameAppMapper.java new file mode 100644 index 0000000..8b30a95 --- /dev/null +++ b/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 { + @Select("select * from game_app where app_id = #{appId}") + GameApp query(@Param("appId")String appId); +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/mapper/UserMapper.java b/game-dao/src/main/java/awesome/group/game/dao/mapper/UserMapper.java new file mode 100644 index 0000000..2a4838e --- /dev/null +++ b/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 { +} diff --git a/game-dao/src/main/java/awesome/group/game/dao/mapper/WeGameUserMapper.java b/game-dao/src/main/java/awesome/group/game/dao/mapper/WeGameUserMapper.java new file mode 100644 index 0000000..f96c0ef --- /dev/null +++ b/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 { + @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); +} diff --git a/game-service/pom.xml b/game-service/pom.xml new file mode 100644 index 0000000..34507b0 --- /dev/null +++ b/game-service/pom.xml @@ -0,0 +1,69 @@ + + + + game + awesome.group + 1.0-SNAPSHOT + + 4.0.0 + + game-service + + + 17 + 17 + UTF-8 + + + + + awesome.group + game-dao + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.security + spring-security-crypto + 5.6.7 + + + org.springframework.boot + spring-boot-starter-test + + + junit + junit + test + + + com.auth0 + java-jwt + 3.14.0 + + + + com.google.code.gson + gson + + + + + com.squareup.okhttp3 + okhttp + + + + + + + \ No newline at end of file diff --git a/game-service/src/main/java/awesome/group/game/service/UserService.java b/game-service/src/main/java/awesome/group/game/service/UserService.java new file mode 100644 index 0000000..d115ddb --- /dev/null +++ b/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); + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/WxService.java b/game-service/src/main/java/awesome/group/game/service/WxService.java new file mode 100644 index 0000000..26b3678 --- /dev/null +++ b/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 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); + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/bo/Code2SessionBo.java b/game-service/src/main/java/awesome/group/game/service/bo/Code2SessionBo.java new file mode 100644 index 0000000..04f0cc1 --- /dev/null +++ b/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; + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/bo/WxResponse.java b/game-service/src/main/java/awesome/group/game/service/bo/WxResponse.java new file mode 100644 index 0000000..7fdb5c6 --- /dev/null +++ b/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; +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/exception/PaganiException.java b/game-service/src/main/java/awesome/group/game/service/common/exception/PaganiException.java new file mode 100644 index 0000000..4562955 --- /dev/null +++ b/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; + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/exception/PaganiExceptionCode.java b/game-service/src/main/java/awesome/group/game/service/common/exception/PaganiExceptionCode.java new file mode 100644 index 0000000..8d2445a --- /dev/null +++ b/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; +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/log/Const.java b/game-service/src/main/java/awesome/group/game/service/common/log/Const.java new file mode 100644 index 0000000..47c87e6 --- /dev/null +++ b/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"; +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/log/IPLogConfig.java b/game-service/src/main/java/awesome/group/game/service/common/log/IPLogConfig.java new file mode 100644 index 0000000..a9b02f7 --- /dev/null +++ b/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; + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/log/L.java b/game-service/src/main/java/awesome/group/game/service/common/log/L.java new file mode 100644 index 0000000..63a9d7a --- /dev/null +++ b/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); + } + +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/log/PaganiLogger.java b/game-service/src/main/java/awesome/group/game/service/common/log/PaganiLogger.java new file mode 100644 index 0000000..a7dd4bc --- /dev/null +++ b/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 mLoggers = new ConcurrentHashMap(); + + 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; + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/log/Status.java b/game-service/src/main/java/awesome/group/game/service/common/log/Status.java new file mode 100644 index 0000000..edd947e --- /dev/null +++ b/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 +} diff --git a/game-service/src/main/java/awesome/group/game/service/common/response/R.java b/game-service/src/main/java/awesome/group/game/service/common/response/R.java new file mode 100644 index 0000000..0eabe00 --- /dev/null +++ b/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 { + 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; + } + +} diff --git a/game-service/src/main/java/awesome/group/game/service/constant/TokenConstants.java b/game-service/src/main/java/awesome/group/game/service/constant/TokenConstants.java new file mode 100644 index 0000000..d9f7362 --- /dev/null +++ b/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"; +} diff --git a/game-service/src/main/java/awesome/group/game/service/util/EncryptUtil.java b/game-service/src/main/java/awesome/group/game/service/util/EncryptUtil.java new file mode 100644 index 0000000..8f9c857 --- /dev/null +++ b/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; + } +} diff --git a/game-service/src/main/java/awesome/group/game/service/util/HttpUtils.java b/game-service/src/main/java/awesome/group/game/service/util/HttpUtils.java new file mode 100644 index 0000000..d9488df --- /dev/null +++ b/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 postForm(String url, Map query, Map form, + Map headers, Class dataType) { + FormBody.Builder bodyBuilder = new FormBody.Builder(); + for (Map.Entry kv : form.entrySet()) { + bodyBuilder.add(kv.getKey(), kv.getValue()); + } + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + for (Map.Entry 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 postJson(String url, Object body, Map headers, Class 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 get(String url, Map queryStr, Map headers, Class dataType) { + HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder(); + for (Map.Entry 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 doHttpExecute(String msg, Request request, Class 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); + } + } + +} diff --git a/game-service/src/main/java/awesome/group/game/service/util/JwtUtils.java b/game-service/src/main/java/awesome/group/game/service/util/JwtUtils.java new file mode 100644 index 0000000..81837c0 --- /dev/null +++ b/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); + } +} diff --git a/game-web/pom.xml b/game-web/pom.xml new file mode 100644 index 0000000..287a7cc --- /dev/null +++ b/game-web/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + + + game + awesome.group + 1.0-SNAPSHOT + + + game-web + + + awesome.group + game-dao + 1.0-SNAPSHOT + + + awesome.group + game-service + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/game-web/src/main/java/awesome/group/Application.java b/game-web/src/main/java/awesome/group/Application.java new file mode 100644 index 0000000..7910c10 --- /dev/null +++ b/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); + } +} diff --git a/game-web/src/main/java/awesome/group/RequestContext.java b/game-web/src/main/java/awesome/group/RequestContext.java new file mode 100644 index 0000000..4972330 --- /dev/null +++ b/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> THREAD_LOCAL = new ThreadLocal<>(); + + + public static void init(HttpServletRequest request, HttpServletResponse response, Integer userId) { + Map 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); + } + + +} diff --git a/game-web/src/main/java/awesome/group/aop/RestApi.java b/game-web/src/main/java/awesome/group/aop/RestApi.java new file mode 100644 index 0000000..41c089d --- /dev/null +++ b/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 { +} diff --git a/game-web/src/main/java/awesome/group/aop/RestApiAop.java b/game-web/src/main/java/awesome/group/aop/RestApiAop.java new file mode 100644 index 0000000..3375980 --- /dev/null +++ b/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; + } +} diff --git a/game-web/src/main/java/awesome/group/controller/LoginController.java b/game-web/src/main/java/awesome/group/controller/LoginController.java new file mode 100644 index 0000000..cf9ea40 --- /dev/null +++ b/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 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 updateUserInfo(@RequestParam String rawData, @RequestParam String signature) { + Integer userId = RequestContext.getUid(); + wxService.updateUserInfo(userId, rawData, signature); + return new R<>(R.CODE_SUCCESS, "", null); + } + +} diff --git a/game-web/src/main/java/awesome/group/interceptor/InterceptorConfig.java b/game-web/src/main/java/awesome/group/interceptor/InterceptorConfig.java new file mode 100644 index 0000000..04b9395 --- /dev/null +++ b/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"); + } +} diff --git a/game-web/src/main/java/awesome/group/interceptor/JwtInterceptor.java b/game-web/src/main/java/awesome/group/interceptor/JwtInterceptor.java new file mode 100644 index 0000000..e445ea6 --- /dev/null +++ b/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 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; + } +} diff --git a/game-web/src/main/resources/application-default.yml b/game-web/src/main/resources/application-default.yml new file mode 100644 index 0000000..eb4054e --- /dev/null +++ b/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 \ No newline at end of file diff --git a/game-web/src/main/resources/application-test.yml b/game-web/src/main/resources/application-test.yml new file mode 100644 index 0000000..9436eb5 --- /dev/null +++ b/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 + diff --git a/game-web/src/main/resources/logback-spring.xml b/game-web/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..5bfa38f --- /dev/null +++ b/game-web/src/main/resources/logback-spring.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/game-web/src/main/resources/logconfig.xml b/game-web/src/main/resources/logconfig.xml new file mode 100644 index 0000000..1e7729d --- /dev/null +++ b/game-web/src/main/resources/logconfig.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + INFO + + ${LOG_HOME}/biz.log + + ${LOG_HOME}/biz.log.%d{yyyyMMddHH} + 72 + true + + + ${ENCODER_PATTERN} + + + + + + 0 + + 64 + + + + + + + + + + ${LOG_HOME}/trace.log + + ${LOG_HOME}/trace.log.%d{yyyyMMddHH} + 72 + true + + + ${TRACE_ENCODER_PATTERN} + + + + + + + 0 + + 64 + + + + + + + + ${LOG_HOME}/api.log + + ${LOG_HOME}/api.log.%d{yyyyMMddHH} + 24 + true + + + ${API_ENCODER_PATTERN} + + + + + + + 0 + + 64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5a7b098 --- /dev/null +++ b/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + + awesome.group + game + 1.0-SNAPSHOT + + game-dao + game-service + game-web + + pom + + 17 + 1.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + 3.1.0 + + + + + + mysql + mysql-connector-java + 8.0.16 + + + + com.baomidou + mybatis-plus-boot-starter + 3.5.3 + + + + + com.squareup.okhttp3 + okhttp + 4.11.0 + + + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + true + + + + compile + + jar + + + + + + + + diff --git a/run b/run new file mode 100755 index 0000000..44a7de8 --- /dev/null +++ b/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 diff --git a/stop b/stop new file mode 100755 index 0000000..aee87fd --- /dev/null +++ b/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 \ No newline at end of file