Browse Source

新增用户和存档后台接口

v1.0
许孟阳 6 days ago
parent
commit
45862fa4c7
  1. 5
      java/application.properties
  2. 46
      java/src/main/java/vip/xumy/idle/server/conf/Configer.java
  3. 49
      java/src/main/java/vip/xumy/idle/server/ctrl/ArchiveController.java
  4. 22
      java/src/main/java/vip/xumy/idle/server/ctrl/PublicController.java
  5. 18
      java/src/main/java/vip/xumy/idle/server/mapper/IArchiveMapper.java
  6. 4
      java/src/main/java/vip/xumy/idle/server/mapper/IUserMapper.java
  7. 26
      java/src/main/java/vip/xumy/idle/server/pojo/Archive.java
  8. 18
      java/src/main/java/vip/xumy/idle/server/pojo/User.java
  9. 38
      java/src/main/java/vip/xumy/idle/server/service/ArchiveService.java
  10. 51
      java/src/main/java/vip/xumy/idle/server/service/UserService.java
  11. 205
      java/src/main/java/vip/xumy/idle/server/util/LoginUtil.java
  12. 1
      java/src/main/resources/application.properties
  13. 15
      src/api/base.ts
  14. 11
      src/api/index.ts
  15. 10
      src/views/archive.vue
  16. 14
      vue.config.js

5
java/application.properties

@ -1,4 +1,7 @@
# 程序自身数据源配置 # 程序自身数据源配置
spring.datasource.url=jdbc:mysql://10.100.0.108:3306/idle_game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true spring.datasource.url=jdbc:mysql://10.100.0.108:3306/idle_game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.datasource.username=root spring.datasource.username=root
spring.datasource.password=mBMjp2v74c7MzhC/5RGeXF1V3E+AcRFs1f5OH6PDHi3nWaM3njaaoewswq8Sl7/AY631t0sONVDG672pX4mFpZx/8xex8BJP3uX1wUu9NGpTCSHskb5cD6KZMNV4jNsfoqxFRyJq8yk86djPsCfR4ch0sPnLH+LCg9XY1DAw8szh93QnKDkiImq2JLkaIwG3R3t8dNWv1wVoMR6vVecPsEUyPJu5vsrvJhjP3uAL7jZYJVGZG6bkrpV3R6I6mja0QnTdF41NCL5Ex0TINSi7GKnrALjZ0qWcT9fe2bTUCKq50+CtVEAQnEz2ZJpYUaBZXJbHh4OrUyqjAmA5s7IelQ== spring.datasource.password=123456
login.token.timeout=10080
login.token.domain=

46
java/src/main/java/vip/xumy/idle/server/conf/Configer.java

@ -0,0 +1,46 @@
package vip.xumy.idle.server.conf;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
/** Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Configuration
public class Configer {
@Bean
public HttpMessageConverter<?> configureMessageConverters() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.DisableCircularReferenceDetect
);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
return converter;
}
}

49
java/src/main/java/vip/xumy/idle/server/ctrl/ArchiveController.java

@ -0,0 +1,49 @@
package vip.xumy.idle.server.ctrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.xumy.core.pojo.com.BaseResponse;
import vip.xumy.idle.server.pojo.Archive;
import vip.xumy.idle.server.service.ArchiveService;
import vip.xumy.idle.server.util.LoginUtil;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@RestController
@RequestMapping("archive")
public class ArchiveController {
@Autowired
private ArchiveService archiveService;
@PostMapping
public BaseResponse saveArchive(@RequestBody Archive archive) {
String userId = LoginUtil.getUserId();
if (userId == null) {
return new BaseResponse(true, "请先登录");
}
archive.setUsername(userId);
archiveService.saveOrUpdate(archive);
return new BaseResponse(true, "存档保存成功");
}
@GetMapping
public BaseResponse getArchive(String version) {
String userId = LoginUtil.getUserId();
Archive archive = archiveService.getByKey(userId, version);
if (archive == null) {
return new BaseResponse(false, "未查询到你的存档");
}
return new BaseResponse(true, archive.getArchive());
}
}

22
java/src/main/java/vip/xumy/idle/server/ctrl/PublicController.java

@ -1,5 +1,6 @@
package vip.xumy.idle.server.ctrl; package vip.xumy.idle.server.ctrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@ -8,7 +9,10 @@ import org.springframework.web.bind.annotation.RestController;
import vip.xumy.core.pojo.com.BaseResponse; import vip.xumy.core.pojo.com.BaseResponse;
import vip.xumy.idle.server.pojo.SocketMsg; import vip.xumy.idle.server.pojo.SocketMsg;
import vip.xumy.idle.server.pojo.User;
import vip.xumy.idle.server.service.UserService;
import vip.xumy.idle.server.service.WebSocketService; import vip.xumy.idle.server.service.WebSocketService;
import vip.xumy.idle.server.util.LoginUtil;
/** /**
* Ownership belongs to the company * Ownership belongs to the company
@ -20,6 +24,8 @@ import vip.xumy.idle.server.service.WebSocketService;
@RestController @RestController
@RequestMapping("public") @RequestMapping("public")
public class PublicController { public class PublicController {
@Autowired
private UserService userService;
@GetMapping("socket/num") @GetMapping("socket/num")
public BaseResponse getSocketNum() { public BaseResponse getSocketNum() {
@ -31,5 +37,21 @@ public class PublicController {
WebSocketService.sendMessage(new SocketMsg<String>("update", notify)); WebSocketService.sendMessage(new SocketMsg<String>("update", notify));
return new BaseResponse(); return new BaseResponse();
} }
@PostMapping("login")
public BaseResponse login(@RequestBody User param) {
User user = userService.login(param);
if (user == null) {
return new BaseResponse(false, "登录失败,用户名或密码错误");
}
LoginUtil.saveLoginInfo(user);
return new BaseResponse(user);
}
@GetMapping("login")
public BaseResponse getLogin() {
User user = LoginUtil.getUserInfo();
return new BaseResponse(user);
}
} }

18
java/src/main/java/vip/xumy/idle/server/mapper/IArchiveMapper.java

@ -0,0 +1,18 @@
package vip.xumy.idle.server.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xumy.idle.server.pojo.Archive;
/** Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Mapper
public interface IArchiveMapper extends BaseMapper<Archive> {
}

4
java/src/main/java/vip/xumy/idle/server/mapper/IUserMapper.java

@ -16,8 +16,8 @@ import vip.xumy.idle.server.pojo.User;
public interface IUserMapper extends BaseMapper<User> { public interface IUserMapper extends BaseMapper<User> {
@Select(""" @Select("""
SELECT username, state FROM user WHERE username = #{username} AND password = #{password} UPDATE user SET last_login = NOW() WHERE username = #{username};
""") """)
User login(User param); User login(String username);
} }

26
java/src/main/java/vip/xumy/idle/server/pojo/Archive.java

@ -0,0 +1,26 @@
package vip.xumy.idle.server.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Setter
@Getter
@TableName("archive")
public class Archive {
private String username;
private String version;
private int lv;
private long coins;
private String archive;
}

18
java/src/main/java/vip/xumy/idle/server/pojo/User.java

@ -1,29 +1,33 @@
package vip.xumy.idle.server.pojo; package vip.xumy.idle.server.pojo;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
/** Ownership belongs to the company /**
* Ownership belongs to the company
* *
* @author:mengyxu * @author:mengyxu
* @date:2025年4月18日 * @date:2025年4月18日
*/ */
@Setter @Setter
@Getter @Getter
@TableName("user") @TableName("user")
public class User { public class User {
private String useranme; @TableId
private String username;
@JSONField(serialize = false)
private String password; private String password;
private String state; private String state;
private String phone; private String phone;
private String idCard; private String idCard;
private String name; private String name;
private String registerTime; private String registerTime;
private String last_login; private String lastLogin;
} }

38
java/src/main/java/vip/xumy/idle/server/service/ArchiveService.java

@ -0,0 +1,38 @@
package vip.xumy.idle.server.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import vip.xumy.idle.server.mapper.IArchiveMapper;
import vip.xumy.idle.server.pojo.Archive;
/** Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Service
public class ArchiveService {
@Autowired
private IArchiveMapper archiveMapper;
public void saveOrUpdate(Archive archive) {
Archive exit = getByKey(archive.getUsername(), archive.getVersion());
if(exit == null) {
archiveMapper.insert(archive);
}else {
archiveMapper.updateById(archive);
}
}
public Archive getByKey(String username, String version) {
QueryWrapper<Archive> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
wrapper.eq("version", version);
return archiveMapper.selectOne(wrapper);
}
}

51
java/src/main/java/vip/xumy/idle/server/service/UserService.java

@ -0,0 +1,51 @@
package vip.xumy.idle.server.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.xumy.core.utils.DateUtil;
import vip.xumy.core.utils.StringUtil;
import vip.xumy.idle.server.mapper.IUserMapper;
import vip.xumy.idle.server.pojo.User;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Service
public class UserService {
@Autowired
private IUserMapper userMapper;
public User login(User param) {
String username = param.getUsername();
String password = param.getPassword();
if (StringUtil.isEmpty(username, password)) {
return null;
}
User user = getById(username);
if (user != null) {
if (password.equals(user.getPassword())) {
userMapper.login(username);
return user;
} else {
return null;
}
} else {
String time = DateUtil.format();
param.setState("0");
param.setRegisterTime(time);
param.setLastLogin(time);
userMapper.insert(param);
return param;
}
}
public User getById(String username) {
return userMapper.selectById(username);
}
}

205
java/src/main/java/vip/xumy/idle/server/util/LoginUtil.java

@ -0,0 +1,205 @@
package vip.xumy.idle.server.util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import vip.xumy.core.golbal.GlobalBuffer;
import vip.xumy.core.pojo.com.Cache;
import vip.xumy.core.utils.StringUtil;
import vip.xumy.idle.server.pojo.User;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2024年3月5日
*/
//@Log4j2
@Component
public class LoginUtil {
public static final String TIKEN_KEY_PREFIX = "token-";
public static final String LOGIN_COOKIE_NAME = "token";
@Value("${login.token.timeout}")
public void setTimeout(Integer timeout) {
LoginUtil.timeout = timeout;
}
private static Integer timeout;
@Value("${login.token.domain}")
public void setDomain(String domain) {
LoginUtil.domain = domain;
}
private static String domain;
private static HttpServletRequest request;
@Autowired
public void setRequest(HttpServletRequest request) {
LoginUtil.request = request;
}
private static HttpServletResponse response;
@Autowired
public void setResponse(HttpServletResponse response) {
LoginUtil.response = response;
}
private static String getTokenKey(String userId) {
return TIKEN_KEY_PREFIX + userId;
}
public static boolean isLogin(String userId) {
Cache cache = GlobalBuffer.getCache(getTokenKey(userId));
return !Cache.isEmpty(cache);
}
public static void remveLoginInfo(String userId) {
String tokenKey = LoginUtil.getTokenKey(userId);
Cache token = GlobalBuffer.getCache(tokenKey);
if (!Cache.isEmpty(token)) {
String value = token.getValue();
GlobalBuffer.removeCache(value.substring(0, 10));
GlobalBuffer.removeCache(tokenKey);
}
}
public static void saveLoginInfo(User user) {
// 删除旧的token信息
String userId = user.getUsername();
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId));
if (!Cache.isEmpty(exitToken)) {
String value = exitToken.getValue();
GlobalBuffer.removeCache(value.substring(0, 10));
}
// 计算新的token
String ip = getIpAddr();
String seq = GlobalBuffer.getSeq();
String token = seq + StringUtil.md5(user.getUsername() + ip + System.currentTimeMillis(), false);
// 保存用户token
GlobalBuffer.addCache(LoginUtil.getTokenKey(userId), new Cache(token, timeout * 60));
// 保存token的用户信息
GlobalBuffer.addCache(seq, new Cache(user, timeout * 60));
LoginUtil.addToken(token, response);
}
private static void addToken(String token, HttpServletResponse response) {
Cookie cookie = new Cookie(LOGIN_COOKIE_NAME, token);
if (!StringUtil.isEmpty(domain)) {
cookie.setDomain(domain);
}
cookie.setPath("/");
response.addCookie(cookie);
}
public static User getUserInfo(String token, boolean refresh) {
if (StringUtil.isEmpty(token)) {
token = getToken();
}
User empty = new User();
if (StringUtil.isEmpty(token) || token.length() != 42) {
return empty;
}
Cache userCache = GlobalBuffer.getCache(token.substring(0, 10));
if (Cache.isEmpty(userCache)) {
return empty;
}
User user = userCache.getValue();
String userId = user.getUsername();
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId));
if (Cache.isEmpty(exitToken)) {
return empty;
}
if (StringUtil.equals(token, exitToken.getValue())) {
if (refresh) {
userCache.refresh();
exitToken.refresh();
}
return user;
}
return empty;
}
public static String getUserId() {
return getUserInfo(null, false).getUsername();
}
public static String getUserIdAndRefresh() {
return getUserInfo(null, true).getUsername();
}
public static User getUserInfo() {
return getUserInfo(null, false);
}
public static void loginOut() {
String token = LoginUtil.getToken();
if (!StringUtil.isEmpty(token)) {
String seq = token.substring(0, 10);
Cache userCache = GlobalBuffer.getCache(seq);
if (!Cache.isEmpty(userCache)) {
User user = userCache.getValue();
String userId = user.getUsername();
GlobalBuffer.removeCache(getTokenKey(userId));
}
GlobalBuffer.removeCache(seq);
}
}
public static String getToken() {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return null;
}
for (Cookie cookie : cookies) {
if (LOGIN_COOKIE_NAME.equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;
}
/**
* 获取访问者IP
*
* 在一般情况下使用Request.getRemoteAddr()即可但是经过nginx等反向代理软件后这个方法会失效
*
* 本方法先从Header中获取X-Real-IP如果不存在再从X-Forwarded-For获得第一个IP(,分割) 如果还不存在则调用Request
* .getRemoteAddr()
*
* @param request
* @return
*/
public static String getIpAddr() {
String ip = request.getHeader("X-Real-IP");
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
ip = request.getHeader("X-Forwarded-For");
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(',');
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
} else {
return request.getRemoteAddr();
}
}
}

1
java/src/main/resources/application.properties

@ -35,4 +35,3 @@ pagehelper.params=count=countSql
pagehelper.returnPageInfo=check pagehelper.returnPageInfo=check
version.num=1.0.1 version.num=1.0.1
version.date=2025-03-07 version.date=2025-03-07
disk.info.path=

15
src/api/base.ts

@ -0,0 +1,15 @@
export const post = (url, data) => {
const options = {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
};
return new Promise((reslove, reject) => {
fetch(url, options)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error('Error:', error));
});
};

11
src/api/index.ts

@ -0,0 +1,11 @@
import { post } from './base';
let commit;
export const setCommit = (data) => {
commit = data;
};
export const login = (param) => {
post('api/public/login', param);
};

10
src/views/archive.vue

@ -10,10 +10,13 @@
</div> </div>
<div class="footer"> <div class="footer">
<button class="button" @click="copyArchive(archive)">{{ t('copyArchive.0') }}</button> <button class="button" @click="copyArchive(archive)">{{ t('copyArchive.0') }}</button>
<!-- <button class="button" @click="copyOldArchive">{{ t('copyArchive.3') }}</button> -->
<button class="button" @click="pasteArchive">{{ t('pasteArchive.0') }}</button> <button class="button" @click="pasteArchive">{{ t('pasteArchive.0') }}</button>
<button class="button" @click="importArchive">{{ t('importArchive.0') }}</button> <button class="button" @click="importArchive">{{ t('importArchive.0') }}</button>
</div> </div>
<div class="footer">
<button class="button" @click="uploadArchive">上传存档</button>
<button class="button" @click="uploadArchive">下载存档</button>
</div>
</Dialog> </Dialog>
</template> </template>
@ -25,10 +28,12 @@ import { useI18n } from "vue3-i18n";
import { Tooltip, Dialog } from "@/components" import { Tooltip, Dialog } from "@/components"
import { menu_icons } from "@/config"; import { menu_icons } from "@/config";
import { getArchive, AES_CBC_ENCRYPT, AES_CBC_DECRYPT, checkImportArchive, saveArchive, replace, archive_version } from "@/tool"; import { getArchive, AES_CBC_ENCRYPT, AES_CBC_DECRYPT, checkImportArchive, saveArchive, replace, archive_version } from "@/tool";
import { setCommit, login } from "@/api";
const { t } = useI18n(); const { t } = useI18n();
const { state, commit, dispatch } = useStore(); const { state, commit, dispatch } = useStore();
setCommit(commit);
const showArchive = computed(() => { const showArchive = computed(() => {
return state.curMenu == 'archive'; return state.curMenu == 'archive';
}); });
@ -67,7 +72,7 @@ const copyArchive = (archive) => {
} }
} }
const copyOldArchive = () => { const uploadArchive = () => {
const archive = localStorage.getItem('transmigration_game_archive') || ''; const archive = localStorage.getItem('transmigration_game_archive') || '';
copyArchive(archive); copyArchive(archive);
} }
@ -118,6 +123,7 @@ const keydown = (e) => {
} }
onMounted(() => { onMounted(() => {
document.addEventListener('keydown', keydown); document.addEventListener('keydown', keydown);
login({ username: 'mengyxu', password: '123456' });
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.removeEventListener('keydown', keydown); document.removeEventListener('keydown', keydown);

14
vue.config.js

@ -2,5 +2,17 @@ const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({ module.exports = defineConfig({
productionSourceMap: false, productionSourceMap: false,
transpileDependencies: true, transpileDependencies: true,
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_BASE_URL,
// 允许跨域
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': '',
},
},
},
},
}); });

Loading…
Cancel
Save