This commit is contained in:
2026-04-15 15:19:28 +08:00
commit 03229f23d4
159 changed files with 12538 additions and 0 deletions

33
旧的java项目/.gitignore vendored Normal file
View File

@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

Binary file not shown.

View File

@@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

120
旧的java项目/AGENTS.md Normal file
View File

@@ -0,0 +1,120 @@
AGENTS.md for this repository
Purpose
- This document guides agent-like contributors (human or AI) on how to build, lint, test, and style the codebase.
- It also captures preferences or constraints used by the team and by automated agents operating in this repo.
Scope
- Build, test, and lint commands for common environments (Node/TS, Python, Go, Rust, Java).
- Code style guidelines: imports, formatting, types, naming, error handling, tests, and documentation.
- Cursor rules and Copilot rules inclusion if present in the repo.
- How to handle running a single test and how to extend tests locally.
1) Quick start: common commands
- Build (preferred entry point):
- Node/TypeScript: npm run build (or yarn build)
- Python: python -m build or your project-specific build script
- Go: go build ./...
- Rust: cargo build
- Lint:
- Node/TypeScript: npm run lint (or yarn lint)
- Python: ruff check . | flake8 or your projects linter
- Go: golangci-lint run
- Rust: cargo clippy
- Test:
- Node/TS: npm test (or yarn test)
- Python: pytest
- Go: go test ./...
- Rust: cargo test
- Note: If your repo uses a mixed tech stack, prefer using the language-specific script in package.json or equivalent courier scripts.
2) Run a single test (typical patterns)
- Node / Jest
- Run a specific test by name: npm test -- -t "should render the component"
- Run a specific file: npm test -- path/to/file.test.js
- Python / Pytest
- Run tests matching a keyword: pytest -k "test_name_substring" -q
- Run a specific file: pytest tests/test_module.py -q
- Go
- Run a single test by name: go test -run TestName ./...
- Rust / Cargo
- Exact test: cargo test -- --exact TestName
- Run a file-like subset: cargo test -- 'pattern'
- Java / Maven or Gradle
- Maven: mvn -Dtest=MyTest#testMethod test
- Gradle: ./gradlew test --tests "com.example.MyTest.testMethod"
3) Code style guidelines
<A) Imports and modules>
- Group imports into three blocks: standard library, third-party, and first-party modules.
- Order blocks alphabetically within each group; separate blocks with a newline.
- Avoid wildcard imports; prefer explicit imports.
- For TS/JS, prefer absolute/alias imports over relative when it improves clarity.
<B) Formatting and tooling>
- Use the projects formatter (Prettier, gofmt, black, etc.) with the configured settings.
- Respect the repositorys line length (commonly 100-120 chars). Break long lines at logical points.
- Use semicolons consistently if the project enforces them; otherwise adhere to the established style.
- Enable and respect lint rules; fix all autofixable issues during code edits.
<C) Types and APIs>
- In TypeScript, enable strict type checking; prefer interfaces for public APIs and type aliases for shapes.
- Use readonly modifiers where possible to express intent and optimize immutability guarantees.
- Prefer explicit return types for exported functions and public APIs.
- Avoid any where possible; if necessary, use unknown with proper checks.
<D) Naming conventions>
- Variables and functions: camelCase
- Classes and types: PascalCase
- Constants: UPPER_SNAKE_CASE
- File and module names: kebab-case or snake_case, consistent with project convention
<E) Error handling>
- Do not swallow errors; attach context when rethrowing (e.g., throw new Error(`Context: ${err.message}`)).
- Propagate errors to callers with meaningful messages.
- Use try/catch around IO-bound or network-bound operations and ensure resources are released in finally or via finally-like blocks.
<F) Async/Promises>
- Prefer async/await syntax for readability.
- Handle rejections at the call site when possible; avoid unhandled promises.
- Use Promise.all when performing independent async tasks, but catch and handle failures gracefully.
<G) Tests>
- Tests should be fast, deterministic, and hermetic.
- Use descriptive test names and structure (Arrange-Act-Assert patterns where helpful).
- Isolate external dependencies; mock/stub network/db calls effectively.
- Include tests for error paths and boundary conditions.
<H) Documentation and comments>
- Document non-obvious logic with concise comments; avoid obvious boilerplate.
- Public APIs should have JSDoc / TSdoc-style comments describing inputs, outputs, and side effects.
- Update or add READMEs where necessary to reflect changes in behavior.
<I) Security and compliance>
- Do not log sensitive data; mask secrets in logs.
- Validate inputs and sanitize outputs where appropriate.
- Treat untrusted data carefully; avoid code paths that execute untrusted input without validation.
4) Cursor and Copilot rules
- Cursor rules: If this repo uses Cursor tooling, its rules can live under .cursor/rules/ or .cursorrules. Copy or adapt them into this document when agents are created.
- Copilot rules: If there is .github/copilot-instructions.md, follow its guidance and ensure code generation adheres to the outlined constraints.
- If the repo contains these files, consider linking to them here and summarizing any special constraints applicable to agents.
5) Git workflow and contribution notes
- Do not modify dependencies without explicit approval.
- Keep commits small and focused; write 1-2 sentence messages describing why a change was made, not just what changed.
- For AGENTS.md updates, include a short rationale in the commit message.
- Prefer small, reviewed edits over sweeping rewrites.
6) Local integration guidance
- Run: npm install or yarn to install deps before building/tests.
- For multi-language repos, ensure the local environment has language runtimes and tooling installed (Node, Python, Go, Rust, etc.).
- Use a clean environment (e.g., nvm, virtualenv) to avoid cross-project contamination.
7) Example usage scenarios
- A single-file feature: create a minimal unit test, run npm test -- -t "feature X" to validate.
- A refactor: run lint and then a subset of tests; fix issues flagged by lints before merging.
- A CI-like dry run: run npm ci; npm run build; npm test; and report failures with minimal noise.
Notes
- If you want me to tailor this file to the exact repo, I can incorporate the actual existing AGENTS.md content (if present) or sync with Cursor/Copilot rules after inspecting the repo. Right now this is a solid, language-agnostic baseline.

View File

@@ -0,0 +1,41 @@
package cn.itcast.client;
import cn.itcast.protocol.MessageCodecSharable;
import cn.itcast.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ChatClient {
public static void main(String[] args) {
NioEventLoopGroup group = new NioEventLoopGroup();
LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.group(group);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ProcotolFrameDecoder());
ch.pipeline().addLast(LOGGING_HANDLER);
ch.pipeline().addLast(MESSAGE_CODEC);
}
});
Channel channel = bootstrap.connect("localhost", 9020).sync().channel();
channel.closeFuture().sync();
} catch (Exception e) {
// log.error("client error", e);
} finally {
group.shutdownGracefully();
}
}
}

View File

@@ -0,0 +1,19 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public abstract class AbstractResponseMessage extends Message {
private boolean success;
private String reason;
public AbstractResponseMessage() {
}
public AbstractResponseMessage(boolean success, String reason) {
this.success = success;
this.reason = reason;
}
}

View File

@@ -0,0 +1,26 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class ChatRequestMessage extends Message {
private String content;
private String to;
private String from;
public ChatRequestMessage() {
}
public ChatRequestMessage(String from, String to, String content) {
this.from = from;
this.to = to;
this.content = content;
}
@Override
public int getMessageType() {
return ChatRequestMessage;
}
}

View File

@@ -0,0 +1,26 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class ChatResponseMessage extends AbstractResponseMessage {
private String from;
private String content;
public ChatResponseMessage(boolean success, String reason) {
super(success, reason);
}
public ChatResponseMessage(String from, String content) {
this.from = from;
this.content = content;
}
@Override
public int getMessageType() {
return ChatResponseMessage;
}
}

View File

@@ -0,0 +1,23 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupChatRequestMessage extends Message {
private String content;
private String groupName;
private String from;
public GroupChatRequestMessage(String from, String groupName, String content) {
this.content = content;
this.groupName = groupName;
this.from = from;
}
@Override
public int getMessageType() {
return GroupChatRequestMessage;
}
}

View File

@@ -0,0 +1,24 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupChatResponseMessage extends AbstractResponseMessage {
private String from;
private String content;
public GroupChatResponseMessage(boolean success, String reason) {
super(success, reason);
}
public GroupChatResponseMessage(String from, String content) {
this.from = from;
this.content = content;
}
@Override
public int getMessageType() {
return GroupChatResponseMessage;
}
}

View File

@@ -0,0 +1,23 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
import java.util.Set;
@Data
@ToString(callSuper = true)
public class GroupCreateRequestMessage extends Message {
private String groupName;
private Set<String> members;
public GroupCreateRequestMessage(String groupName, Set<String> members) {
this.groupName = groupName;
this.members = members;
}
@Override
public int getMessageType() {
return GroupCreateRequestMessage;
}
}

View File

@@ -0,0 +1,18 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupCreateResponseMessage extends AbstractResponseMessage {
public GroupCreateResponseMessage(boolean success, String reason) {
super(success, reason);
}
@Override
public int getMessageType() {
return GroupCreateResponseMessage;
}
}

View File

@@ -0,0 +1,22 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupJoinRequestMessage extends Message {
private String groupName;
private String username;
public GroupJoinRequestMessage(String username, String groupName) {
this.groupName = groupName;
this.username = username;
}
@Override
public int getMessageType() {
return GroupJoinRequestMessage;
}
}

View File

@@ -0,0 +1,18 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupJoinResponseMessage extends AbstractResponseMessage {
public GroupJoinResponseMessage(boolean success, String reason) {
super(success, reason);
}
@Override
public int getMessageType() {
return GroupJoinResponseMessage;
}
}

View File

@@ -0,0 +1,19 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupMembersRequestMessage extends Message {
private String groupName;
public GroupMembersRequestMessage(String groupName) {
this.groupName = groupName;
}
@Override
public int getMessageType() {
return GroupMembersRequestMessage;
}
}

View File

@@ -0,0 +1,22 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
import java.util.Set;
@Data
@ToString(callSuper = true)
public class GroupMembersResponseMessage extends Message {
private Set<String> members;
public GroupMembersResponseMessage(Set<String> members) {
this.members = members;
}
@Override
public int getMessageType() {
return GroupMembersResponseMessage;
}
}

View File

@@ -0,0 +1,22 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupQuitRequestMessage extends Message {
private String groupName;
private String username;
public GroupQuitRequestMessage(String username, String groupName) {
this.groupName = groupName;
this.username = username;
}
@Override
public int getMessageType() {
return GroupQuitRequestMessage;
}
}

View File

@@ -0,0 +1,17 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class GroupQuitResponseMessage extends AbstractResponseMessage {
public GroupQuitResponseMessage(boolean success, String reason) {
super(success, reason);
}
@Override
public int getMessageType() {
return GroupQuitResponseMessage;
}
}

View File

@@ -0,0 +1,26 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class LoginRequestMessage extends Message {
private String username;
private String password;
private String nickname;
public LoginRequestMessage() {
}
public LoginRequestMessage(String username, String password, String nickname) {
this.username = username;
this.password = password;
this.nickname = nickname;
}
@Override
public int getMessageType() {
return LoginRequestMessage;
}
}

View File

@@ -0,0 +1,13 @@
package cn.itcast.message;
import lombok.Data;
import lombok.ToString;
@Data
@ToString(callSuper = true)
public class LoginResponseMessage extends AbstractResponseMessage {
@Override
public int getMessageType() {
return LoginResponseMessage;
}
}

View File

@@ -0,0 +1,54 @@
package cn.itcast.message;
import lombok.Data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
@Data
public abstract class Message implements Serializable {
public static Class<?> getMessageClass(int messageType) {
return messageClasses.get(messageType);
}
private int sequenceId;
private int messageType;
public abstract int getMessageType();
public static final int LoginRequestMessage = 0;
public static final int LoginResponseMessage = 1;
public static final int ChatRequestMessage = 2;
public static final int ChatResponseMessage = 3;
public static final int GroupCreateRequestMessage = 4;
public static final int GroupCreateResponseMessage = 5;
public static final int GroupJoinRequestMessage = 6;
public static final int GroupJoinResponseMessage = 7;
public static final int GroupQuitRequestMessage = 8;
public static final int GroupQuitResponseMessage = 9;
public static final int GroupChatRequestMessage = 10;
public static final int GroupChatResponseMessage = 11;
public static final int GroupMembersRequestMessage = 12;
public static final int GroupMembersResponseMessage = 13;
private static final Map<Integer, Class<?>> messageClasses = new HashMap<>();
static {
messageClasses.put(LoginRequestMessage, LoginRequestMessage.class);
messageClasses.put(LoginResponseMessage, LoginResponseMessage.class);
messageClasses.put(ChatRequestMessage, ChatRequestMessage.class);
messageClasses.put(ChatResponseMessage, ChatResponseMessage.class);
messageClasses.put(GroupCreateRequestMessage, GroupCreateRequestMessage.class);
messageClasses.put(GroupCreateResponseMessage, GroupCreateResponseMessage.class);
messageClasses.put(GroupJoinRequestMessage, GroupJoinRequestMessage.class);
messageClasses.put(GroupJoinResponseMessage, GroupJoinResponseMessage.class);
messageClasses.put(GroupQuitRequestMessage, GroupQuitRequestMessage.class);
messageClasses.put(GroupQuitResponseMessage, GroupQuitResponseMessage.class);
messageClasses.put(GroupChatRequestMessage, GroupChatRequestMessage.class);
messageClasses.put(GroupChatResponseMessage, GroupChatResponseMessage.class);
messageClasses.put(GroupMembersRequestMessage, GroupMembersRequestMessage.class);
messageClasses.put(GroupMembersResponseMessage, GroupMembersResponseMessage.class);
}
}

View File

@@ -0,0 +1,62 @@
package cn.itcast.protocol;
import cn.itcast.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
@Slf4j
@ChannelHandler.Sharable
public class MessageCodec extends ByteToMessageCodec<Message> {
@Override
public void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
// // 1. 4 字节的魔数
// out.writeBytes(new byte[]{1, 2, 3, 4});
// // 2. 1 字节的版本,
// out.writeByte(1);
// // 3. 1 字节的序列化方式 jdk 0 , json 1
// out.writeByte(0);
// // 4. 1 字节的指令类型
// out.writeByte(msg.getMessageType());
// // 5. 4 个字节
//// out.writeInt(msg.getSequenceId());
// // 无意义,对齐填充
// out.writeByte(0xff);
// // 6. 获取内容的字节数组
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(bos);
// oos.writeObject(msg);
// byte[] bytes = bos.toByteArray();
// // 7. 长度
// out.writeInt(bytes.length);
// // 8. 写入内容
// out.writeBytes(bytes);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int magicNum = in.readInt();
byte version = in.readByte();
byte serializerType = in.readByte();
byte messageType = in.readByte();
int sequenceId = in.readInt();
in.readByte();
int length = in.readInt();
byte[] bytes = new byte[length];
in.readBytes(bytes, 0, length);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
Message message = (Message) ois.readObject();
// log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
// log.debug("{}", message);
out.add(message);
}
}

View File

@@ -0,0 +1,66 @@
package cn.itcast.protocol;
import cn.itcast.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
@Slf4j
@ChannelHandler.Sharable
/**
* 必须和 LengthFieldBasedFrameDecoder 一起使用,确保接到的 ByteBuf 消息是完整的
*/
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
@Override
protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> outList) throws Exception {
// ByteBuf out = ctx.alloc().buffer();
// // 1. 4 字节的魔数
// out.writeBytes(new byte[]{1, 2, 3, 4});
// // 2. 1 字节的版本,
// out.writeByte(1);
// // 3. 1 字节的序列化方式 jdk 0 , json 1
// out.writeByte(0);
// // 4. 1 字节的指令类型
// out.writeByte(msg.getMessageType());
// // 5. 4 个字节
// out.writeInt(msg.getSequenceId());
// // 无意义,对齐填充
// out.writeByte(0xff);
// // 6. 获取内容的字节数组
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(bos);
// oos.writeObject(msg);
// byte[] bytes = bos.toByteArray();
// // 7. 长度
// out.writeInt(bytes.length);
// // 8. 写入内容
// out.writeBytes(bytes);
// outList.add(out);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
int magicNum = in.readInt();
byte version = in.readByte();
byte serializerType = in.readByte();
byte messageType = in.readByte();
int sequenceId = in.readInt();
in.readByte();
int length = in.readInt();
byte[] bytes = new byte[length];
in.readBytes(bytes, 0, length);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
Message message = (Message) ois.readObject();
// log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
// log.debug("{}", message);
out.add(message);
}
}

View File

@@ -0,0 +1,14 @@
package cn.itcast.protocol;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
public class ProcotolFrameDecoder extends LengthFieldBasedFrameDecoder {
public ProcotolFrameDecoder() {
this(1024, 12, 4, 0, 0);
}
public ProcotolFrameDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
}
}

View File

@@ -0,0 +1,44 @@
package cn.itcast.server;
import cn.itcast.protocol.MessageCodecSharable;
import cn.itcast.protocol.ProcotolFrameDecoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ChatServer {
public static void main(String[] args) {
NioEventLoopGroup boss = new NioEventLoopGroup();
NioEventLoopGroup worker = new NioEventLoopGroup();
LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.group(boss, worker);
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ProcotolFrameDecoder());
ch.pipeline().addLast(LOGGING_HANDLER);
ch.pipeline().addLast(MESSAGE_CODEC);
}
});
Channel channel = serverBootstrap.bind(9020).sync().channel();
channel.closeFuture().sync();
} catch (InterruptedException e) {
// log.error("server error", e);
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
}

View File

@@ -0,0 +1,15 @@
package cn.itcast.server.service;
/**
* 用户管理接口
*/
public interface UserService {
/**
* 登录
* @param username 用户名
* @param password 密码
* @return 登录成功返回 true, 否则返回 false
*/
boolean login(String username, String password);
}

View File

@@ -0,0 +1,10 @@
package cn.itcast.server.service;
public abstract class UserServiceFactory {
private static UserService userService = new UserServiceMemoryImpl();
public static UserService getUserService() {
return userService;
}
}

View File

@@ -0,0 +1,25 @@
package cn.itcast.server.service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class UserServiceMemoryImpl implements UserService {
private Map<String, String> allUserMap = new ConcurrentHashMap<>();
{
allUserMap.put("zhangsan", "123");
allUserMap.put("lisi", "123");
allUserMap.put("wangwu", "123");
allUserMap.put("zhaoliu", "123");
allUserMap.put("qianqi", "123");
}
@Override
public boolean login(String username, String password) {
String pass = allUserMap.get(username);
if (pass == null) {
return false;
}
return pass.equals(password);
}
}

View File

@@ -0,0 +1,24 @@
package cn.itcast.server.session;
import lombok.Data;
import java.util.Collections;
import java.util.Set;
@Data
/**
* 聊天组,即聊天室
*/
public class Group {
// 聊天室名称
private String name;
// 聊天室成员
private Set<String> members;
public static final Group EMPTY_GROUP = new Group("empty", Collections.emptySet());
public Group(String name, Set<String> members) {
this.name = name;
this.members = members;
}
}

View File

@@ -0,0 +1,57 @@
package cn.itcast.server.session;
import io.netty.channel.Channel;
import java.util.List;
import java.util.Set;
/**
* 聊天组会话管理接口
*/
public interface GroupSession {
/**
* 创建一个聊天组, 如果不存在才能创建成功, 否则返回 null
* @param name 组名
* @param members 成员
* @return 成功时返回组对象, 失败返回 null
*/
Group createGroup(String name, Set<String> members);
/**
* 加入聊天组
* @param name 组名
* @param member 成员名
* @return 如果组不存在返回 null, 否则返回组对象
*/
Group joinMember(String name, String member);
/**
* 移除组成员
* @param name 组名
* @param member 成员名
* @return 如果组不存在返回 null, 否则返回组对象
*/
Group removeMember(String name, String member);
/**
* 移除聊天组
* @param name 组名
* @return 如果组不存在返回 null, 否则返回组对象
*/
Group removeGroup(String name);
/**
* 获取组成员
* @param name 组名
* @return 成员集合, 没有成员会返回 empty set
*/
Set<String> getMembers(String name);
/**
* 获取组成员的 channel 集合, 只有在线的 channel 才会返回
* @param name 组名
* @return 成员 channel 集合
*/
List<Channel> getMembersChannel(String name);
}

View File

@@ -0,0 +1,10 @@
package cn.itcast.server.session;
public abstract class GroupSessionFactory {
private static GroupSession session = new GroupSessionMemoryImpl();
public static GroupSession getGroupSession() {
return session;
}
}

View File

@@ -0,0 +1,55 @@
package cn.itcast.server.session;
import io.netty.channel.Channel;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class GroupSessionMemoryImpl implements GroupSession {
private final Map<String, Group> groupMap = new ConcurrentHashMap<>();
@Override
public Group createGroup(String name, Set<String> members) {
Group group = new Group(name, members);
return groupMap.putIfAbsent(name, group);
}
@Override
public Group joinMember(String name, String member) {
return groupMap.computeIfPresent(name, (key, value) -> {
// value.getMembers().add(member);
return value;
});
}
@Override
public Group removeMember(String name, String member) {
return groupMap.computeIfPresent(name, (key, value) -> {
// value.getMembers().remove(member);
return value;
});
}
@Override
public Group removeGroup(String name) {
return groupMap.remove(name);
}
@Override
public Set<String> getMembers(String name) {
// return groupMap.getOrDefault(name, Group.EMPTY_GROUP).getMembers();
return null;
}
@Override
public List<Channel> getMembersChannel(String name) {
return getMembers(name).stream()
.map(member -> SessionFactory.getSession().getChannel(member))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,46 @@
package cn.itcast.server.session;
import io.netty.channel.Channel;
/**
* 会话管理接口
*/
public interface Session {
/**
* 绑定会话
* @param channel 哪个 channel 要绑定会话
* @param username 会话绑定用户
*/
void bind(Channel channel, String username);
/**
* 解绑会话
* @param channel 哪个 channel 要解绑会话
*/
void unbind(Channel channel);
/**
* 获取属性
* @param channel 哪个 channel
* @param name 属性名
* @return 属性值
*/
Object getAttribute(Channel channel, String name);
/**
* 设置属性
* @param channel 哪个 channel
* @param name 属性名
* @param value 属性值
*/
void setAttribute(Channel channel, String name, Object value);
/**
* 根据用户名获取 channel
* @param username 用户名
* @return channel
*/
Channel getChannel(String username);
}

View File

@@ -0,0 +1,10 @@
package cn.itcast.server.session;
public abstract class SessionFactory {
private static Session session = new SessionMemoryImpl();
public static Session getSession() {
return session;
}
}

View File

@@ -0,0 +1,47 @@
package cn.itcast.server.session;
import io.netty.channel.Channel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SessionMemoryImpl implements Session {
private final Map<String, Channel> usernameChannelMap = new ConcurrentHashMap<>();
private final Map<Channel, String> channelUsernameMap = new ConcurrentHashMap<>();
private final Map<Channel,Map<String,Object>> channelAttributesMap = new ConcurrentHashMap<>();
@Override
public void bind(Channel channel, String username) {
usernameChannelMap.put(username, channel);
channelUsernameMap.put(channel, username);
channelAttributesMap.put(channel, new ConcurrentHashMap<>());
}
@Override
public void unbind(Channel channel) {
String username = channelUsernameMap.remove(channel);
usernameChannelMap.remove(username);
channelAttributesMap.remove(channel);
}
@Override
public Object getAttribute(Channel channel, String name) {
return channelAttributesMap.get(channel).get(name);
}
@Override
public void setAttribute(Channel channel, String name, Object value) {
channelAttributesMap.get(channel).put(name, value);
}
@Override
public Channel getChannel(String username) {
return usernameChannelMap.get(username);
}
@Override
public String toString() {
return usernameChannelMap.toString();
}
}

316
旧的java项目/mvnw vendored Normal file
View File

@@ -0,0 +1,316 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

188
旧的java项目/mvnw.cmd vendored Normal file
View File

@@ -0,0 +1,188 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

134
旧的java项目/pom.xml Normal file
View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>sjkbf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sjkbf</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.14</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!-- MyBatis-Plus Generator改用官方版本 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- freemarker 模板引擎(没有用原生的模板引擎)-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.16</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version> <!-- 版本号可根据需要调整 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,27 @@
package com.example.sjkbf;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.Date;
/**
* @author lnj
* createTime 2018-11-07 22:37
**/
@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
}
}

View File

@@ -0,0 +1,141 @@
package com.example.sjkbf;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CodeGenerator {
//依赖
// compile group: 'com.baomidou', name: 'mybatis-plus-generator', version: '3.3.1.tmp'
// compile group: 'org.freemarker', name: 'freemarker', version: '2.3.31'
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + "");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotBlank(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
//获得当前文件路径
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
// gc.setOutputDir("D:\\test");
gc.setAuthor("bozhiqiang");
////是否打开资源管理器
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
//service接口置生成的service接口名首字母是为I
gc.setServiceName("%sService");
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://110.42.251.214:3306/rindro?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC&allowPublicKeyRetrieval=true");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("Yosin0102!");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(null);
pc.setParent("com.example.zyk");
//设置实体类包名 可不设 默认entity
// pc.setEntity("entity");
//设置mapper包名 可不设 默认 mapper
// pc.setMapper("mapper");
//设置service 包名 可不设默认 service
// pc.setService("service");
//设置controller 包名 可不设默认 controller
// pc.setController("controller")
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/"
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
//表映射实体---去除表前缀
strategy.setNaming(NamingStrategy.underline_to_camel);
//字段映射实体---去除下划线
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//实体类开启Lombok
strategy.setEntityLombokModel(true);
//控制层接口使用Rest
strategy.setRestControllerStyle(true);
//设置要映射的表名
//String[] tableNames = {"表名1","表名2","","表名3","表名x"};
//strategy.setInclude(tableNames);
// strategy.setInclude("blog_tags","course","links","sys_settings","user_record"," user_say"); // 设置要映射的表名
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
//去除表前缀
strategy.setTablePrefix("m_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}

View File

@@ -0,0 +1,110 @@
package com.example.sjkbf;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.LineHandler;
import cn.hutool.core.io.file.Tailer;
import cn.hutool.core.io.watch.SimpleWatcher;
import cn.hutool.core.io.watch.WatchMonitor;
import cn.hutool.core.io.watch.watchers.DelayWatcher;
import cn.hutool.log.StaticLog;
import com.example.sjkbf.common.FileManage;
import com.example.sjkbf.controller.AccountCargoController;
import com.example.sjkbf.service.impl.ProjectPerServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.WatchEvent;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Configuration //1.主要用于标记配置类兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class SaticScheduleTask {
@Autowired
public ProjectPerServiceImpl projectPerService;
@Autowired
FileManage fileManage;
private static ConfigurableApplicationContext context;
//3.添加定时任务
// @Scheduled(cron = "0 0 0/2 * * ?")
@PostConstruct
public void configureTasks() throws Exception {
fileManage.init();
projectPerService.initInfo();
WatchMonitor all = WatchMonitor.createAll(fileManage.getScriptfile(), new DelayWatcher(new SimpleWatcher(){
@Override
public void onModify(WatchEvent<?> event, Path currentPath) {
try {
projectPerService.initInfo();
}catch (Exception e){
e.printStackTrace();
StaticLog.error("重载项目配置文件出现异常");
}
System.out.println("重载配置文件");
}
}, 500));
all.setMaxDepth(4);
all.start();
// Tailer tailer = new Tailer(FileUtil.file(fileManage.getConfigfile()), new LineHandler() {
// @Override
// public void handle(String s) {
// try {
// projectPerService.initInfo();
//
// }catch (Exception e){
// e.printStackTrace();
// StaticLog.error("重载项目配置文件出现异常");
// }
// System.out.println("重载配置文件");
// }
// }, 1);
//
// //新建一个线程
// Thread thread = new Thread(
// tailer::start
// );
// thread.start();
}
@Autowired
AccountCargoController cargoController;
// @Scheduled(cron = "0 0 1 * * ?")
// private void configureTasks2(){
// cargoController.save();
// }
public static void main(String[] args) {
System.out.println(2620+1940+1450+741 - ((40+37 +94 +20)*2) -70);
System.out.println(6299*0.7);
System.out.println(4409-25-150-68-200-300-100-50+6+25-200-750-100-400-30-50+70+6-200-50);
}
}

View File

@@ -0,0 +1,59 @@
package com.example.sjkbf;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import java.io.File;
import java.io.IOException;
import java.util.Date;
@SpringBootApplication()
public class SjkbfApplication {
private static ConfigurableApplicationContext context;
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(SjkbfApplication.class, args);
// 添加自定义关闭钩子,打印触发源
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("=====================================");
System.out.println("=== 自定义ShutdownHook触发开始定位原因 ===");
System.out.println("触发时间:" + new java.util.Date());
System.out.println("当前线程:" + Thread.currentThread().getName());
// 打印所有线程的栈轨迹,找到触发关闭的源头
Thread.getAllStackTraces().forEach((thread, stackTraces) -> {
// 只打印关键线程(减少日志量)
if (thread.getName().contains("ShutdownHook") || thread.getName().contains("main")
|| thread.getName().contains("Task") || thread.getName().contains("Timer")) {
System.out.println("\n线程名称" + thread.getName() + " (状态:" + thread.getState() + ")");
for (StackTraceElement elem : stackTraces) {
System.out.println("\t" + elem);
}
}
});
System.out.println("=== ShutdownHook触发原因定位结束 ===");
System.out.println("=====================================");
System.out.println("=== 应用触发关闭,开始重启上下文 ===");
// 关闭当前上下文
context.close();
// 重新启动上下文
context = SpringApplication.run(SjkbfApplication.class, args);
}, "Custom-Exit-Detector"));
}
}

View File

@@ -0,0 +1,41 @@
package com.example.sjkbf.common;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
public class FileManage {
@Value("${pro.configfile}")
private String configfile;
@Value("${pro.userfile}")
private String file;
@Value("${pro.filemap}")
private String filemap;
@Value("${pro.scriptfile}")
private String scriptfile;
@Value("${pro.dps}")
private String dpsfile;
private String dpsScriptfile;
public void init(){
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
dpsScriptfile = file +"dpsScript\\";
}else {
dpsScriptfile = file +"dpsScript/";
}
}
}

View File

@@ -0,0 +1,11 @@
package com.example.sjkbf.config.Configuration;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {
}

View File

@@ -0,0 +1,43 @@
package com.example.sjkbf.config.Configuration;
import com.example.sjkbf.entity.AuthUser;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CurrentUserIdResolver());
}
public static class CurrentUserIdResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CurrentUserId.class);
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String userName = (String)authentication.getPrincipal();
return userName;
}
}
}

View File

@@ -0,0 +1,44 @@
package com.example.sjkbf.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
// 1. 创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 允许的域名(生产环境建议明确指定,而非使用通配符)
config.addAllowedOriginPattern("*"); // Spring Boot 2.4+ 使用 allowedOriginPatterns
// config.addAllowedOrigin("http://localhost:8080"); // 明确指定域名
// 允许的请求头
config.addAllowedHeader("*");
// 允许的 HTTP 方法
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("OPTIONS"); // 预检请求需要
// 是否允许发送 Cookie
config.setAllowCredentials(true);
// 预检请求缓存时间(秒)
config.setMaxAge(3600L);
// 2. 注册 CORS 配置应用到所有路径
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
// 3. 返回 CORS 过滤器
return new CorsFilter(source);
}
}

View File

@@ -0,0 +1,87 @@
package com.example.sjkbf.config;
import com.example.sjkbf.util.JwtTokenUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 1. 从请求头获取 Token
String token = jwtTokenUtil.getTokenFromRequest(request);
try {
// 2. Token 存在且有效(基础验证:签名、过期时间)
if (token != null && jwtTokenUtil.validateToken(token)) {
// 3. 直接从 Token 中解析用户信息和权限(无需查库)
String username = jwtTokenUtil.getUsernameFromToken(token);
List<GrantedAuthority> authorities = jwtTokenUtil.getAuthoritiesFromToken(token)
.stream()
.map(SimpleGrantedAuthority ::new)
.collect(Collectors.toList());
// 4. 构建 Authentication 对象(权限来自 Token
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
username, // 主体可以是用户名(或自定义 User 对象)
null, // 凭证(密码)无需存储
authorities
);
// 5. 存入 SecurityContext后续鉴权直接使用 Token 中的权限)
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}catch (JwtException e){
sendErrorResponse(response, 4011, "请重新登录");
return;
}
catch (Exception e) {
// Token 解析失败(如篡改、过期),清理上下文
SecurityContextHolder.clearContext();
sendErrorResponse(response, 4013, "认证失败");
logger.error("认证失败:" + e.getMessage());
return;
}
// 6. 继续过滤器链
chain.doFilter(request, response);
}
// 发送 JSON 错误响应
private void sendErrorResponse(HttpServletResponse response, int code, String message)
throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> errorData = new HashMap<>();
errorData.put("code", code);
errorData.put("msg", message);
response.getWriter().write(new ObjectMapper().writeValueAsString(errorData));
}
}

View File

@@ -0,0 +1,26 @@
package com.example.sjkbf.config;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 插入时自动填充创建时间
this.strictInsertFill(metaObject, "createTime", Date.class, DateUtil.date());
// 插入时自动填充更新时间
this.strictInsertFill(metaObject, "updateTime", Date.class, DateUtil.date());
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时自动填充更新时间
this.strictUpdateFill(metaObject, "updateTime", Date.class, DateUtil.date());
}
}

View File

@@ -0,0 +1,16 @@
package com.example.sjkbf.config;
import com.google.common.util.concurrent.RateLimiter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RateLimitConfig {
// 总带宽限制15MB/s = 15 * 1024 * 1024 B/s
private static final double TOTAL_BANDWIDTH = 15 * 1024 * 1024;
@Bean
public RateLimiter globalRateLimiter() {
return RateLimiter.create(TOTAL_BANDWIDTH);
}
}

View File

@@ -0,0 +1,134 @@
package com.example.sjkbf.config;
import com.example.sjkbf.config.exception.CustomAuthenticationEntryPoint;
import com.example.sjkbf.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
/**
* Spring Security 核心配置类
* - 继承 WebSecurityConfigurerAdapter适配 Spring Boot 2.5.x
* - 启用方法级权限控制(@PreAuthorize
* - 配置 JWT 过滤器、密码加密、认证规则等
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用方法级权限注解
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService; // 用户服务(需自行实现)
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; // JWT 过滤器
@Autowired
private CorsFilter corsFilter; // 跨域过滤器(需自行配置)
// 认证失败处理器
@Autowired
private CustomAuthenticationEntryPoint unauthorizedHandler;
// @Autowired
// private LogoutSuccessHandlerImpl logoutSuccessHandler; // 注销成功处理器
/**
* 密码加密器(强制使用 BCrypt
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 认证管理器(暴露为 Bean供登录接口调用
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 配置用户认证来源(如数据库)
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//注册验证用户的处理器 和密码加密器
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
/**
* 核心安全配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// ==================== 基础配置 ====================
.csrf().disable() // 关闭 CSRFREST API 无状态,无需 CSRF
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话
.and()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler) // 认证失败处理(如未登录访问受保护接口)
.accessDeniedHandler(new AccessDeniedHandlerImpl()) // 权限不足处理(已登录但无权限)
.and()
// ==================== 授权规则 ====================
.authorizeRequests()
// 开放接口(无需认证)
.antMatchers(
"/login",
"/register",
"/changePassword",
"/dps/*",
"/dps/*/*",
"/rindro/download",
"/rindro/download/*",
"/rindro/mp4",
"/rindro/getversion",
"/rindro/addgold",
"/rindro/getimg/*/*",
"/rindro/getthumb/*/*",
"/rindro/getmp4/*/*",
"/rindro/getmp42/*/*",
"/script/*",
"/api/videos/*/*",
"/zf/callback",
"/rindro/download/*/*"
).permitAll()
// 其他所有请求需认证
.anyRequest().authenticated()
.and()
// ==================== 过滤器配置 ====================
// 添加 CORS 过滤器在最前
.addFilterBefore(corsFilter, LogoutFilter.class)
// 添加 JWT 过滤器在登录认证过滤器之前
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// ==================== 注销配置 ====================
// .logout()
// .logoutUrl("/logout") // 注销接口
// .logoutSuccessHandler(logoutSuccessHandler) // 注销成功处理(返回 JSON
// .deleteCookies("JSESSIONID"); // 删除 Cookie如果使用
}
}

View File

@@ -0,0 +1,25 @@
package com.example.sjkbf.config;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.controller.AccountCargoController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Date;
@Configuration //1.主要用于标记配置类兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class StartInit {
@Scheduled(cron = "0 0 0 * * ?")
public void configureTasks() throws Exception {
AccountCargoController.a.clear();
}
}

View File

@@ -0,0 +1,31 @@
package com.example.sjkbf.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.resource.EncodedResourceResolver;
import java.util.concurrent.TimeUnit;
@Configuration
public class VideoConfig implements WebMvcConfigurer {
/**
* 配置视频文件缓存策略
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 1. 转码视频资源映射(/tmp/video-transcoded/
registry.addResourceHandler("/transcoded/**")
.addResourceLocations("file:/tmp/video-transcoded/")
.setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
.resourceChain(true)
.addResolver(new EncodedResourceResolver());
// 2. 原始视频资源映射(/root/rindro/Script/Project/
registry.addResourceHandler("/original/**")
.addResourceLocations("file:/root/rindro/Script/Project/")
.setCacheControl(CacheControl.noCache())
.resourceChain(false);
}
}

View File

@@ -0,0 +1,36 @@
package com.example.sjkbf.config.exception;
import cn.hutool.log.StaticLog;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException {
// 默认处理,实际应由全局异常处理器接管
// 设置响应状态码和内容类型
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
// 构建自定义错误信息
Map<String, Object> errorData = new HashMap<>();
errorData.put("code", 4010);
errorData.put("msg", "此页面需要登录后访问");
// 写入 JSON 响应
response.getWriter().write(new ObjectMapper().writeValueAsString(errorData));
}
}

View File

@@ -0,0 +1,70 @@
package com.example.sjkbf.config.exception;
import cn.hutool.log.StaticLog;
import com.example.sjkbf.entity.CommonResult;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理用户名密码错误异常Spring Security 默认抛出 BadCredentialsException
@ExceptionHandler(BadCredentialsException.class)
public ResponseEntity<?> handleBadCredentials(BadCredentialsException e) {
Map<String, Object> response = new HashMap<>();
response.put("msg", "用户名或密码错误");
response.put("code", 4010);
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(response);
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<CommonResult<String>> responseEntity(RuntimeException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.CREATED)
.body(CommonResult.failed(201,e.getMessage()));
}
/**
* 处理视频文件不存在异常
*/
@ExceptionHandler(FileNotFoundException.class)
public ResponseEntity<String> handleFileNotFound(FileNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("Video file not found: " + e.getMessage());
}
/**
* 处理转码异常
*/
@ExceptionHandler(IOException.class)
public ResponseEntity<String> handleTranscodeError(IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Video processing error: " + e.getMessage());
}
@ExceptionHandler(ClientAbortException.class)
public void handleClientAbortException(ClientAbortException e) {
// 仅打印警告日志,无需向上抛出
StaticLog.info("客户端主动断开连接: {}", e.getMessage());
}
}

View File

@@ -0,0 +1,328 @@
package com.example.sjkbf.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.log.StaticLog;
import com.example.sjkbf.common.FileManage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import cn.hutool.core.io.file.FileReader;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>
* InnoDB free: 11264 kB 前端控制器
* </p>
*
* @author bozhiqiang
* @since 2022-04-03
*/
@RestController
@RequestMapping("/dps")
public class AccountCargoController {
@Autowired
FileManage fileManage;
public static Map<String,Integer> a=new HashMap<>();
@RequestMapping("/login")
public int login(HttpServletRequest request) {
String ipAddress = getIpAddress(request);
a.put(ipAddress,a.size()+1);
return a.size();
}
@RequestMapping("/getversion")
public String getversion() {
FileReader fileReader = new FileReader(fileManage.getDpsfile()+"Application/Proj.ifo");
String result = fileReader.readString();
return result;
}
@RequestMapping("/getclientversion")
public String getclientversion() {
FileReader fileReader = new FileReader(fileManage.getDpsfile()+"Marketplace/Proj.ifo");
String result = fileReader.readString();
return result;
}
@RequestMapping("/getlist")
public String getlist() {
File[] ls = FileUtil.ls(fileManage.getDpsfile()+"Script");
StringBuilder list = new StringBuilder("{ \"list\":[");
for (File l : ls) {
FileReader fileReader = new FileReader(l+"/"+"Proj.ifo");
list.append(fileReader.readString()).append(",");
}
list.deleteCharAt(list.length() - 1);
list.append("]}");
return list.toString();
}
@RequestMapping("/getadvertisement")
public String getadvertisement() {
File[] ls = FileUtil.ls(fileManage.getDpsfile()+"Advertisement");
//按文件夹名字排序
Arrays.sort(ls, Comparator.comparing(File::getName));
StringBuilder list = new StringBuilder("{ \"list\":[");
for (File l : ls) {
FileReader fileReader = new FileReader(l+"/"+"info.ifo");
list.append(fileReader.readString()).append(",");
}
list.deleteCharAt(list.length() - 1);
list.append("]}");
return list.toString();
}
// 使用正则表达式捕获所有字符(包括斜杠)
@PostMapping("/download/{colonPath}")
public ResponseEntity<Resource> download(
@PathVariable String colonPath) throws Exception {
// 1. 解码中文路径
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
// System.out.println("接收到参数: " + decodedPath);
// 2. 将冒号还原为斜杠
String realPath = decodedPath.replace(":", "/");
// System.out.println("真实路径: " + realPath);
StaticLog.info( "文件下载1: " + realPath );
// 3. 构建绝对路径
Path baseDir = Paths.get(fileManage.getDpsfile()+"Script").toAbsolutePath().normalize();
Path targetPath = baseDir.resolve(realPath).normalize();
// 4. 安全校验(防止路径穿越)
if (!targetPath.startsWith(baseDir)) {
System.err.println("非法路径尝试: " + realPath);
return ResponseEntity.status(403).build();
}
// 5. 返回文件
Resource resource = new FileSystemResource(targetPath);
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
// 使用正则表达式捕获所有字符(包括斜杠)
@PostMapping ("/download2/{colonPath}")
public ResponseEntity<Resource> download2(
@PathVariable String colonPath) throws Exception {
// 1. 解码中文路径
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
// System.out.println("接收到参数: " + decodedPath);
// 2. 将冒号还原为斜杠
String realPath = decodedPath.replace(":", "/");
// System.out.println("真实路径: " + realPath);
// 3. 构建绝对路径
Path baseDir = Paths.get(fileManage.getDpsfile()+"Application").toAbsolutePath().normalize();
Path targetPath = baseDir.resolve(realPath).normalize();
// 4. 安全校验(防止路径穿越)
if (!targetPath.startsWith(baseDir)) {
System.err.println("非法路径尝试: " + realPath);
return ResponseEntity.status(403).build();
}
// 5. 返回文件
Resource resource = new FileSystemResource(targetPath);
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
@RequestMapping("/download3/{colonPath}")
public ResponseEntity<Resource> download3(
@PathVariable String colonPath) throws Exception {
// 1. 解码中文路径
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
// System.out.println("接收到参数: " + decodedPath);
// 2. 将冒号还原为斜杠
String realPath = decodedPath.replace(":", "/");
// System.out.println("真实路径: " + realPath);
// 3. 构建绝对路径
Path baseDir = Paths.get(fileManage.getDpsfile()+"Advertisement").toAbsolutePath().normalize();
Path targetPath = baseDir.resolve(realPath).normalize();
// 4. 安全校验(防止路径穿越)
if (!targetPath.startsWith(baseDir)) {
System.err.println("非法路径尝试: " + realPath);
return ResponseEntity.status(403).build();
}
// 5. 返回文件
Resource resource = new FileSystemResource(targetPath);
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
public static void main(String[] args) {
File[] ls = FileUtil.ls("C:\\Users\\12134\\Downloads\\Advertisement");
StringBuilder list = new StringBuilder("{ \"list\":[");
for (File l : ls) {
FileReader fileReader = new FileReader(l+"\\"+"info.ifo");
list.append(fileReader.readString()).append(",");
}
list.deleteCharAt(list.length() - 1);
list.append("]}");
System.out.println(list.toString());
}
//添加
public static String processCommand(String input) {
// 按行处理以保留格式
String[] lines = input.split("\n");
StringBuilder result = new StringBuilder();
for (String line : lines) {
// 处理包含df_game_r的命令行包括注释行
if (line.contains("./df_game_r siroco")) {
line = processGameLine(line);
}
result.append(line).append("\n");
}
return result.toString().trim();
}
private static String processGameLine(String line) {
// 检查是否是注释行
boolean isCommented = line.trim().startsWith("#");
String workingLine = isCommented ? line.substring(line.indexOf("#") + 1) : line;
// 检查是否已有LD_PRELOAD
Matcher preloadMatcher = Pattern.compile("LD_PRELOAD\\s*=\\s*\"([^\"]*)\"").matcher(workingLine);
if (preloadMatcher.find()) {
// 已有LD_PRELOAD的情况确保包含目标库
String libs = preloadMatcher.group(1).trim();
if (!libs.contains("/dp_s/lib/libAurora.so")) {
String newLibs = "/dp_s/lib/libAurora.so" + (libs.isEmpty() ? "" : " " + libs);
workingLine = workingLine.replaceFirst("LD_PRELOAD\\s*=\\s*\"[^\"]*\"",
"LD_PRELOAD=\" " + newLibs + "\"");
}
} else {
// 没有LD_PRELOAD的情况添加
workingLine = workingLine.replaceFirst("(\\./df_game_r\\s+siroco)",
"LD_PRELOAD=\" /dp_s/lib/libAurora.so\" $1");
}
return isCommented ? "#" + workingLine : workingLine;
}
//删除
public static String cleanLdPreload(String input) {
// 使用Matcher的region功能保留所有换行符
StringBuilder result = new StringBuilder();
Pattern pattern = Pattern.compile(
"(LD_PRELOAD\\s*=\\s*\")([^\"]*?)/dp_s/lib/libAurora\\.so([^\"]*?)(\")|" +
"(LD_PRELOAD\\s*=\\s*\"\\s*\")"
);
Matcher matcher = pattern.matcher(input);
int lastPos = 0;
while (matcher.find()) {
// 添加匹配前的内容(包含所有换行符)
result.append(input, lastPos, matcher.start());
// 处理匹配到的内容
if (matcher.group(1) != null) { // 情况1包含Aurora.so
String replacement = matcher.group(1) +
matcher.group(2) +
matcher.group(3) +
matcher.group(4);
// 如果替换后变成LD_PRELOAD="",则完全删除
if (replacement.equals("LD_PRELOAD=\"\"")) {
// 不添加任何内容(相当于删除)
} else {
result.append(replacement);
}
} else { // 情况2空的LD_PRELOAD
// 完全跳过不添加(删除)
}
lastPos = matcher.end();
}
// 添加剩余内容
result.append(input.substring(lastPos));
return result.toString();
}
public static String getIpAddress(HttpServletRequest request) {
// 获取请求的IP地址
String ipAddress = request.getRemoteAddr();
// 如果应用部署在反向代理或负载均衡器后面可以通过X-Forwarded-For头部获取真实IP地址
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
ipAddress = forwardedFor.split(",")[0];
}
return ipAddress;
}
}

View File

@@ -0,0 +1,103 @@
package com.example.sjkbf.controller;
import com.example.sjkbf.entity.CommonResult;
import com.example.sjkbf.entity.DTO.LoginRequest;
import com.example.sjkbf.entity.DTO.LoginResponse;
import com.example.sjkbf.service.UserService;
import com.example.sjkbf.util.JwtTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
@RestController
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity<?> login(@Valid @RequestBody LoginRequest request) {
// 1. 创建认证令牌(未认证状态)
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword());
// 2. 执行认证Spring Security 自动调用 UserDetailsService
Authentication authentication = authenticationManager.authenticate(authenticationToken);
// 3. 认证成功,生成 JWT
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String token = jwtTokenUtil.generateToken(userDetails);
// 4. 提取权限信息
List<String> roles = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
// 5. 返回响应
return ResponseEntity.ok(
new LoginResponse("Bearer "+token, userDetails.getUsername(), roles)
);
}
// 用户注册接口
@PostMapping("/register")
public ResponseEntity<CommonResult<String>> register(@Valid @RequestBody LoginRequest request) {
if (request.getUsername()==null|| request.getUsername().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"用户名为空"));
}
if (request.getPassword()==null|| request.getPassword().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"密码为空"));
}
if (request.getQq()==null|| request.getQq().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"安全口令为空"));
}
// 检查用户名是否已存在
if (userService.isUsernameExist(request.getUsername())) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"用户名已存在"));
}
// 保存用户
userService.registerUser(request);
return ResponseEntity.ok(CommonResult.success("注册成功"));
}
//找回密码
@PostMapping("/changePassword")
public ResponseEntity<CommonResult<String>> changePassword(@Valid @RequestBody LoginRequest request) {
if (request.getUsername()==null|| request.getUsername().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"用户名为空"));
}
if (request.getPassword()==null|| request.getPassword().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"密码为空"));
}
if (request.getQq()==null|| request.getQq().isEmpty()) {
return ResponseEntity.status(HttpStatus.CREATED).body(CommonResult.failed(201,"安全口令为空"));
}
// 保存用户
userService.updatePassword(request);
return ResponseEntity.ok(CommonResult.success("修改成功"));
}
}

View File

@@ -0,0 +1,699 @@
package com.example.sjkbf.controller;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.common.FileManage;
import com.example.sjkbf.config.Configuration.CurrentUserId;
import com.example.sjkbf.entity.*;
import com.example.sjkbf.entity.projectconfig.Project;
import com.example.sjkbf.service.ProjectPerService;
import com.example.sjkbf.service.UserAndServerService;
import com.example.sjkbf.service.UserServerProjectService;
import com.example.sjkbf.service.UserService;
import com.google.common.util.concurrent.RateLimiter;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.*;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 前端控制器
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@RestController
@RequestMapping("/rindro")
public class UserController {
@Autowired
private ProjectPerService projectPerService;
@Autowired
private UserService userService;
@Autowired
private UserAndServerService userAndServerService;
@Autowired
private UserServerProjectService userServerProjectService;
@Autowired
FileManage fileManage;
//下载插件相关内容
@PostMapping("/download")
public ResponseEntity<Object> download(@RequestBody Map<String,String> body) throws Exception {
// //如果不是通用文件就要先检查
// if (!body.get("projectName").contains("通用")) {
// List<UserServerProject> byUserName = userServerProjectService.getByUserName(userName);
// if (byUserName == null) {
// // 若服务器没有该插件,返回错误信息的通用结果
// return new ResponseEntity<>(CommonResult.failed("没有插件授权 无法下载相关内容"), HttpStatus.OK);
// }
// for (UserServerProject userServerProject : byUserName) {
// boolean isExpired = false;
// if (userServerProject.getProjectName().equals(body.get("projectName"))) {
// isExpired =true;
// }
// if (!isExpired){
// return new ResponseEntity<>(CommonResult.failed("没有插件授权 无法下载相关内容"), HttpStatus.OK);
// }
// }
// }
String file = "/root/rindro/download/profile/"+body.get("projectName")+".zip";
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
file = "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\download\\profile\\"+body.get("projectName")+".zip";
}
Path baseDir = Paths.get(file).toAbsolutePath().normalize();
Resource resource = new FileSystemResource(baseDir);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"");
// 返回包含文件资源的通用结果
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
//获得账号信息
@PostMapping("/getInfo")
public ResponseEntity<CommonResult<Map<String,Object>>> getInfo(@CurrentUserId String userName) {
User user = userService.getOne(new QueryWrapper<User>().eq("username", userName));
Map<String, Object> body = new HashMap<>();
body.put("userpoints", user.getGold());
body.put("username", user.getName());
body.put("useravatar", user.getImg());
body.put("uservip", "普通会员");
body.put("usercash", null);
return ResponseEntity.ok(CommonResult.success(body));
}
//
// /**
// * 获得项目的标题文件
// * @param colonPath
// * @return
// * @throws UnsupportedEncodingException
// */
// @RequestMapping("/getimg/{colonPath}")
// public ResponseEntity<Resource> getimg(@PathVariable String colonPath) throws UnsupportedEncodingException {
// String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
//
// Project byName = projectPerService.getByName(decodedPath);
// if (byName==null)return null;
// String imgPath = byName.getImgPath();
//
// String file = "/root/rindro/Script/"+imgPath;
// String os = System.getProperty("os.name").toLowerCase();
// if (os.contains("win")) {
// file = "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\"+imgPath;
// }
//
//
// // 5. 返回文件
// Resource resource = new FileSystemResource(file);
// if (!resource.exists()) {
// return ResponseEntity.notFound().build();
// }
//
// return ResponseEntity.ok()
// .header("Content-Disposition",
// "attachment; filename=\"" + resource.getFilename() + "\"")
// .body(resource);
// }
/**
* 获得项目文件中的图片
* @param colonPath
* @return
* @throws UnsupportedEncodingException
*/
@RequestMapping("/getimg/{colonPath}/{img}")
public ResponseEntity<Resource> getimg2(@PathVariable String colonPath,@PathVariable String img) throws UnsupportedEncodingException {
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
img = URLDecoder.decode(img, "UTF-8");
Project byName = projectPerService.getByName(decodedPath);
if (byName==null)return null;
String imgPath = byName.getImgPath();
String file = "/root/rindro/Script/Project/"+imgPath+"/img/"+img+".png";
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
file = "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\Project\\"+imgPath+"\\img\\"+img+".png";
}
// 5. 返回文件
Resource resource = new FileSystemResource(file);
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
/**
* 获得项目文件中的缩略图使用Thumbnailator
*/
@RequestMapping("/getthumb/{colonPath}/{img}")
public ResponseEntity<Resource> getThumbnailWithLib(
@PathVariable String colonPath,
@PathVariable String img,
@RequestParam(required = false, defaultValue = "200") int width,
@RequestParam(required = false, defaultValue = "200") int height)
throws UnsupportedEncodingException, IOException {
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
img = URLDecoder.decode(img, "UTF-8");
Project byName = projectPerService.getByName(decodedPath);
if (byName == null) return ResponseEntity.notFound().build();
String imgPath = byName.getImgPath();
String originalFile = "/root/rindro/Script/Project/" + imgPath + "/img/" + img + ".png";
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
originalFile = "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\Project\\" + imgPath + "\\img\\" + img + ".png";
}
// 检查原图是否存在
Resource originalResource = new FileSystemResource(originalFile);
if (!originalResource.exists()) {
return ResponseEntity.notFound().build();
}
// 使用Thumbnailator生成缩略图
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Thumbnails.of(originalFile)
.size(width, height)
.outputFormat("png")
.outputQuality(0.8) // 设置输出质量
.toOutputStream(outputStream);
byte[] thumbnailBytes = outputStream.toByteArray();
ByteArrayResource resource = new ByteArrayResource(thumbnailBytes);
String downloadFileName = img + "_thumb_" + width + "x" + height + ".png";
return ResponseEntity.ok()
.header("Content-Type", "image/png")
.header("Content-Disposition", "attachment; filename=\"" + downloadFileName + "\"")
.body(resource);
}
/**
* 获得项目文件中的MP4
* @param colonPath
* @return
* @throws UnsupportedEncodingException
*/
@RequestMapping("/getmp42/{colonPath}/{img}")
public ResponseEntity<Resource> getmp4(@PathVariable String colonPath,@PathVariable String img) throws IOException {
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
img = URLDecoder.decode(img, "UTF-8");
Project byName = projectPerService.getByName(decodedPath);
if (byName==null)return null;
String imgPath = byName.getImgPath();
String file = "/root/rindro/Script/Project/"+imgPath+"/vid/"+img+".mp4";
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
file = "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\Project\\"+imgPath+"\\vid\\"+img+".mp4";
}
// 5. 返回文件
Resource resource = new FileSystemResource(file);
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header("Content-Type", "video/mp4")
// 添加下行强制变为下载行为与Alist一致
.header("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"")
.header("Accept-Ranges", "bytes")
.body(resource);
}
//购买
@PostMapping("/buy")
public ResponseEntity<CommonResult<Object>> buy( @RequestBody Map<String,String> body,@CurrentUserId String userName) throws Exception {
String buy = userService.buy(body.get("ip"), body.get("projectName"), userName);
Map<String, Object> result = new HashMap<>();
result.put("info",buy);
if (buy.equals("购买成功")){
UserServerProject byIPAndName = userServerProjectService.getByIPAndName(body.get("ip"), body.get("projectName"));
DateTime date = DateUtil.date(byIPAndName.getExpirationDate());
String format = DateUtil.format(date, "yyyy-MM-dd");
result.put("endTime",format);
return ResponseEntity.ok(CommonResult.success(result));
}
return ResponseEntity.ok(CommonResult.failed(buy));
}
//充值
@GetMapping("/addgold")
public ResponseEntity<CommonResult<String>> addgold(String userName,Integer gold){
String addgold = userService.addgold(userName,gold);
return ResponseEntity.ok(CommonResult.success(addgold));
}
//转让
@PostMapping("/transfer")
public ResponseEntity<CommonResult<String>> transfer(@RequestBody Map<String,String> body,@CurrentUserId String userName){
String transfer = userService.transfer(userName,body.get("username"), Integer.valueOf(body.get("gold")));
return ResponseEntity.ok(CommonResult.success(transfer));
}
//给账号添加服务器
@PostMapping("/addServer")
public ResponseEntity<CommonResult<String>> addServer(@RequestBody Map<String,String> body,@CurrentUserId String userName){
String addServer = userService.addServer(body.get("ip"),userName,body.get("username"),body.get("password"),body.get("port"));
return ResponseEntity.ok(CommonResult.success(addServer));
}
//给账号删除服务器
@PostMapping("/deleteServer")
public ResponseEntity<CommonResult<String>> deleteServer(@RequestBody Map<String,String> body,@CurrentUserId String userName){
String deleteServer = userService.deleteServer(body.get("ip"), userName);
return ResponseEntity.ok(CommonResult.success(deleteServer));
}
//获得服务器列表
@PostMapping("/getServerList")
public ResponseEntity<CommonResult<List<Map<String,Object>>>> getServerList(@CurrentUserId String userName){
List<UserAndServer> serverList = userAndServerService.getServerList(userName);
// List<String> collect = serverList.stream().map(UserAndServer::getServerIp).collect(Collectors.toList());
List<Map<String, Object> > body = serverList.stream().map(item -> {
Map<String, Object> map = new HashMap<>();
map.put("serverIp", item.getServerIp());
map.put("userName", item.getAccount());
map.put("password", item.getPassword());
map.put("port", item.getPort());
return map;
}
).collect(Collectors.toList());
return ResponseEntity.ok(CommonResult.success(body));
}
//获得服务器信息
@PostMapping("/getServer")
public ResponseEntity<CommonResult<UserAndServer>> getServer(@RequestBody Map<String,String> body,@CurrentUserId String userName){
UserAndServer userAndServer = userAndServerService.getOne(new QueryWrapper<UserAndServer>().eq("user_name", userName).eq("server_ip", body.get("ip")));
return ResponseEntity.ok(CommonResult.success(userAndServer));
}
//获取插件信息
@PostMapping("/getProjectInfoList")
public ResponseEntity<CommonResult<Object>> getProjectInfoList(){
Map<String, Map<String, Object>> body = projectPerService.getProjectInfoList();
return ResponseEntity.ok(CommonResult.success(body));
}
/**
* 获取自己拥有的插件信息
* @return
*/
@PostMapping("/getUserProList")
public ResponseEntity<CommonResult<Object>> getgetUserProList(@RequestBody Map<String,String> body) {
List<UserServerProject> byUserName = userServerProjectService.getpro(body.get("ip"));
Map<String, Map<String, Object>> body2 = projectPerService.getProjectInfoListAll();
Map<String, Map<String, Object>> re =new HashMap<>();
for (UserServerProject userServerProject : byUserName) {
Map<String, Object> objectMap = body2.get(userServerProject.getProjectName());
DateTime date = DateUtil.date(userServerProject.getExpirationDate());
String format = DateUtil.format(date, "yyyy-MM-dd");
objectMap.put("endTime",format);
objectMap.put("open",userServerProject.getOpen());
re.put(userServerProject.getProjectName(),objectMap);
}
return ResponseEntity.ok(CommonResult.success(re));
}
@GetMapping("/download/sh")
public ResponseEntity<Resource> downloadFileSh() {
// 构建文件的完整路径
File file = new File(fileManage.getFile()+"re.sh");
StaticLog.info("请求下载sh脚本"+file);
if (!file.exists()) {
// 如果文件不存在,返回 404 错误
return ResponseEntity.notFound().build();
}
// 创建文件资源对象
Resource resource = new FileSystemResource(file);
// 设置响应头,告知浏览器这是一个附件,需要下载
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + "re.sh");
// 返回响应实体,包含文件资源、响应头和状态码
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
@GetMapping("/download/c")
public ResponseEntity<Resource> downloadFileC() {
// 构建文件的完整路径
return getResourceResponseEntity("download/ndpsm_svr", "ndpsm_svr");
}
@GetMapping("/download/d")
public ResponseEntity<Resource> downloadFileD() {
// 构建文件的完整路径
return getResourceResponseEntity("download/DPS_Login_Gateway", "DPS_Login_Gateway");
}
@GetMapping("/download/djson")
public ResponseEntity<Resource> downloadFileDjson() {
return getResourceResponseEntity("download/config.json", "config.json");
}
@GetMapping("/download/dsh")
public ResponseEntity<Resource> downloadFileDsh() {
return getResourceResponseEntity("download/DpsLoginRestartSh", "DpsLoginRestartSh");
}
@GetMapping("/download/ddsh")
public ResponseEntity<Resource> downloadFileDrsh() {
return getResourceResponseEntity("download/DpsLoginDownloadSh", "DpsLoginDownloadSh");
}
private ResponseEntity<Resource> getResourceResponseEntity(String x, String x1) {
// 构建文件的完整路径
File file = new File(fileManage.getFile() + x);
if (!file.exists()) {
// 如果文件不存在,返回 404 错误
return ResponseEntity.notFound().build();
}
// 创建文件资源对象
Resource resource = new FileSystemResource(file);
// 设置响应头,告知浏览器这是一个附件,需要下载
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + x1);
// 返回响应实体,包含文件资源、响应头和状态码
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
}
@GetMapping("/download/jdk")
public ResponseEntity<Resource> downloadFileJdk() {
// 构建文件的完整路径
return getResourceResponseEntity("jdk", "ndpsm_svr");
}
@Autowired
private RateLimiter globalRateLimiter;
@GetMapping("/download/jar")
public ResponseEntity<Resource> downloadFilejar(HttpServletResponse response) {
File file = new File(fileManage.getFile()+"download/RT.tar.gz");
if (!file.exists()) {
return ResponseEntity.notFound().build();
}
try (InputStream inputStream = Files.newInputStream(file.toPath());
BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = response.getOutputStream()) {
// 设置响应头
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=RT.tar.gz");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setContentLengthLong(file.length());
byte[] buffer = new byte[1024 * 8]; // 8KB 缓冲区
int bytesRead;
// 动态限速:每次读取后根据数据量申请令牌
while ((bytesRead = bis.read(buffer)) != -1) {
// 申请令牌(阻塞直到获取足够令牌)
globalRateLimiter.acquire(bytesRead);
os.write(buffer, 0, bytesRead);
os.flush();
}
} catch (IOException e) {
return ResponseEntity.status(500).build();
}
return ResponseEntity.ok().build();
}
@PostMapping("/download/all")
public ResponseEntity<Resource> downloadFileall(@RequestBody Map<String,String> body,HttpServletResponse response) {
String s = body.get("key");
FileReader fileReader = new FileReader(fileManage.getFilemap());
String result = fileReader.readString();
JSONObject jsonObject = JSONUtil.parseObj(result);
String str = jsonObject.getStr(s);
File file = new File(str);
StaticLog.info("请求下载文件"+file);
if (!file.exists()) {
return ResponseEntity.notFound().build();
}
try (InputStream inputStream = Files.newInputStream(file.toPath());
BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = response.getOutputStream()) {
// 设置响应头
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=RT.tar.gz");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setContentLengthLong(file.length());
byte[] buffer = new byte[1024 * 8]; // 8KB 缓冲区
int bytesRead;
// 动态限速:每次读取后根据数据量申请令牌
while ((bytesRead = bis.read(buffer)) != -1) {
// 申请令牌(阻塞直到获取足够令牌)
globalRateLimiter.acquire(bytesRead);
os.write(buffer, 0, bytesRead);
os.flush();
}
} catch (IOException e) {
return ResponseEntity.status(500).build();
}
return ResponseEntity.ok().build();
}
@RequestMapping("/download/gr")
public ResponseEntity<Resource> downloadFilegr(String body,HttpServletResponse response) {
FileReader fileReader = new FileReader(fileManage.getFilemap());
String result = fileReader.readString();
JSONObject jsonObject = JSONUtil.parseObj(result);
String str = jsonObject.getStr(body);
File file = new File(str);
StaticLog.info("请求下载文件"+file);
if (!file.exists()) {
return ResponseEntity.notFound().build();
}
try (InputStream inputStream = Files.newInputStream(file.toPath());
BufferedInputStream bis = new BufferedInputStream(inputStream);
OutputStream os = response.getOutputStream()) {
// 设置响应头
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+file.getName());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setContentLengthLong(file.length());
byte[] buffer = new byte[1024 * 8]; // 8KB 缓冲区
int bytesRead;
// 动态限速:每次读取后根据数据量申请令牌
while ((bytesRead = bis.read(buffer)) != -1) {
// 申请令牌(阻塞直到获取足够令牌)
globalRateLimiter.acquire(bytesRead);
os.write(buffer, 0, bytesRead);
os.flush();
}
} catch (IOException e) {
return ResponseEntity.status(500).build();
}
return ResponseEntity.ok().build();
}
@RequestMapping("/getversion")
public String getversion() {
FileReader fileReader = new FileReader(fileManage.getFile()+"download/version");
String result = fileReader.readString();
return result;
}
@GetMapping("/getmp4/{colonPath}/{img}")
public ResponseEntity<Resource> streamVideo(
@RequestHeader(value = "Range", required = false) String rangeHeader, @PathVariable String colonPath,@PathVariable String img) {
try {
String decodedPath = URLDecoder.decode(colonPath, "UTF-8");
img = URLDecoder.decode(img, "UTF-8");
Project byName = projectPerService.getByName(decodedPath);
if (byName==null)return null;
String imgPath = byName.getImgPath();
Path videoPath = Paths.get("/root/rindro/Script/Project/"+imgPath+"/vid/"+img+".mp4");
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
videoPath = Paths.get("C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\Project\\"+imgPath+"\\vid\\"+img+".mp4");
}
Resource videoResource = new UrlResource(videoPath.toUri());
if (!videoResource.exists() || !videoResource.isReadable()) {
return ResponseEntity.notFound().build();
}
long contentLength = videoResource.contentLength();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("video/mp4"));
headers.set("Accept-Ranges", "bytes");
if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
String[] ranges = rangeHeader.substring(6).split("-");
long start = Long.parseLong(ranges[0]);
long end = (ranges.length > 1 && !ranges[1].isEmpty())
? Long.parseLong(ranges[1])
: contentLength - 1;
long rangeLength = end - start + 1;
if (start >= contentLength || end >= contentLength) {
return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
.header("Content-Range", "bytes */" + contentLength)
.build();
}
// 获取输入流并跳过起始字节
InputStream inputStream = videoResource.getInputStream();
long skippedBytes = inputStream.skip(start);
if (skippedBytes != start) {
throw new IOException("无法跳过指定字节数");
}
headers.set("Content-Range", "bytes " + start + "-" + end + "/" + contentLength);
headers.setContentLength(rangeLength);
return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
.headers(headers)
.body(new InputStreamResource(inputStream));
} else {
return ResponseEntity.ok()
.headers(headers)
.body(videoResource);
}
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
//根据ip获取插件列表
@PostMapping("/getServerProList")
public ResponseEntity<CommonResult<List<UserServerProject>>> getServerList(@RequestBody Map<String,String> body, @CurrentUserId String userName){
if (userAndServerService.selectCount(body.get("ip"),userName)==0){
return ResponseEntity.ok(CommonResult.success(null));
}
List<UserServerProject> ip = userServerProjectService.getpro(body.get("ip"));
return ResponseEntity.ok(CommonResult.success(ip));
}
//设置用户单机用的key值
@PostMapping("/setKey")
public ResponseEntity<CommonResult<String>> setKey(@RequestBody Map<String,String> body, @CurrentUserId String userName){
String s = userService.setKey(userName, body.get("clientkey"), body.get("serverkey"));
return ResponseEntity.ok(CommonResult.success(s));
}
@PostMapping("/setproopen")
public ResponseEntity<CommonResult<String>> setproOpen(@RequestBody Map<String,String> body, @CurrentUserId String userName){
String s = userServerProjectService.setproOpen(body.get("ip"), body.get("projectName"), body.get("open"),userName);
return ResponseEntity.ok(CommonResult.success(s));
}
}

View File

@@ -0,0 +1,22 @@
package com.example.sjkbf.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author bozhiqiang
* @since 2025-04-19
*/
@RestController
@RequestMapping("/user-server-project")
public class UserServerProjectController {
}

View File

@@ -0,0 +1,344 @@
package com.example.sjkbf.controller;
import com.example.sjkbf.entity.projectconfig.Project;
import com.example.sjkbf.service.ProjectPerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.*;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.net.URLDecoder;
import java.nio.file.*;
import java.text.DecimalFormat;
import java.util.concurrent.*;
@RestController
@RequestMapping("/api")
public class VideoController {
private static final String VIDEO_ROOT = "/root/rindro/Script/Project";
private static final String TRANSCODE_ROOT = "/tmp/video-transcoded";
private final ExecutorService transcodeExecutor = Executors.newFixedThreadPool(4);
@Autowired
private ProjectPerService projectPerService;
private final DecimalFormat durationFormat = new DecimalFormat("0.00");
@GetMapping("/videos/{project}/{videoName}")
public ResponseEntity<Resource> streamVideo(
@PathVariable String project,
@PathVariable String videoName,
@RequestHeader(value = "User-Agent", required = false) String userAgent,
@RequestHeader(value = "Range", required = false) String rangeHeader) throws Exception {
System.out.println("原始参数 - project: " + project + ", videoName: " + videoName);
// project ="project";
// videoName = "0";
// 直接使用 Spring 已经解码的参数
project = projectPerService.getByName(project).getImgPath();
// project = projectPerService.getByName(decodedPath).getImgPath();
Path sourcePath = Paths.get(VIDEO_ROOT, project, "vid", videoName + ".mp4");
// 检查源文件是否存在
if (!Files.exists(sourcePath)) {
System.out.println("源文件不存在: " + sourcePath);
return ResponseEntity.notFound().build();
}
boolean needsTranscode = needsTranscode(sourcePath, userAgent);
if (needsTranscode) {
Path transcodedPath = getTranscodedPath(project, videoName);
// 如果转码文件不存在或正在转码,先返回原始文件
if (!Files.exists(transcodedPath) || isTranscodingInProgress(transcodedPath)) {
// 异步触发转码(如果还没开始的话)
if (!Files.exists(transcodedPath)) {
startTranscode(project, videoName);
}
// 返回原始文件作为降级方案
return buildVideoResponse(sourcePath, rangeHeader, false);
}
return buildVideoResponse(transcodedPath, rangeHeader, true);
} else {
return buildVideoResponse(sourcePath, rangeHeader, false);
}
}
/**
* 改进的转码检测逻辑
*/
private boolean needsTranscode(Path videoPath, String userAgent) throws IOException {
if (!Files.exists(videoPath)) {
throw new FileNotFoundException("视频文件不存在: " + videoPath);
}
// 不再强制为移动设备转码,而是基于实际编码格式判断
try {
// 检测视频编码
String videoCodec = getStreamCodec(videoPath, "v");
String audioCodec = getStreamCodec(videoPath, "a");
// 需要转码的情况:
// 1. 视频不是H.264
// 2. 音频不是AAC或MP3
boolean needTranscode = !"h264".equalsIgnoreCase(videoCodec) ||
(!"aac".equalsIgnoreCase(audioCodec) && !"mp3".equalsIgnoreCase(audioCodec));
System.out.println("视频编码: " + videoCodec + ", 音频编码: " + audioCodec + ", 需要转码: " + needTranscode);
return needTranscode;
} catch (Exception e) {
// 如果检测失败,默认需要转码
System.err.println("编码检测失败,默认需要转码: " + e.getMessage());
return true;
}
}
/**
* 获取音视频流编码
*/
private String getStreamCodec(Path videoPath, String streamType) throws IOException {
Process proc = new ProcessBuilder(
"ffprobe",
"-v", "error",
"-select_streams", streamType + ":0",
"-show_entries", "stream=codec_name",
"-of", "default=noprint_wrappers=1:nokey=1",
videoPath.toString()
).start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String codec = br.readLine();
return codec != null ? codec.trim() : "unknown";
}
}
/**
* 获取转码路径并触发转码
*/
private Path getTranscodedPath(String project, String videoName) {
return Paths.get(TRANSCODE_ROOT, project, videoName + "_h264.mp4");
}
/**
* 启动转码任务
*/
private void startTranscode(String project, String videoName) {
transcodeExecutor.submit(() -> transcodeVideo(project, videoName));
}
/**
* 改进的转码方法 - 使用更兼容的参数
*/
private void transcodeVideo(String project, String videoName) {
Path transcodedPath = getTranscodedPath(project, videoName);
Path tempPath = Paths.get(transcodedPath.toString() + ".tmp");
try {
// 确保目录存在
Files.createDirectories(transcodedPath.getParent());
String source = Paths.get(VIDEO_ROOT, project, "vid", videoName + ".mp4").toString();
// 简化转码命令 - 提高兼容性
String[] cmd = {
"ffmpeg", "-i", source,
"-c:v", "libx264",
"-preset", "medium",
"-crf", "23",
"-profile:v", "high", // 改为high提高质量
"-level", "4.0",
"-c:a", "aac",
"-b:a", "128k",
"-movflags", "+faststart", // 只保留faststart
"-y", tempPath.toString() // 先输出到临时文件
};
System.out.println("执行转码命令: " + String.join(" ", cmd));
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process p = pb.start();
// 读取输出用于调试
try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("FFmpeg: " + line);
}
}
int exitCode = p.waitFor();
if (exitCode == 0) {
// 转码成功,重命名临时文件
Files.move(tempPath, transcodedPath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("转码完成: " + transcodedPath);
} else {
System.err.println("转码失败,退出码: " + exitCode);
Files.deleteIfExists(tempPath);
}
} catch (Exception e) {
System.err.println("转码过程出错: " + e.getMessage());
e.printStackTrace();
try {
Files.deleteIfExists(tempPath);
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
/**
* 检查是否正在转码
*/
private boolean isTranscodingInProgress(Path transcodedPath) {
Path tempPath = Paths.get(transcodedPath.toString() + ".tmp");
return Files.exists(tempPath);
}
/**
* 检查原始文件是否比转码文件新
*/
private boolean isSourceNewer(String project, String videoName, Path transcodedPath) throws IOException {
Path sourcePath = Paths.get(VIDEO_ROOT, project, "vid", videoName + ".mp4");
return Files.getLastModifiedTime(sourcePath).toInstant()
.isAfter(Files.getLastModifiedTime(transcodedPath).toInstant());
}
/**
* 构建视频响应
*/
private ResponseEntity<Resource> buildVideoResponse(Path videoPath, String rangeHeader, boolean isTranscoded)
throws IOException {
if (!Files.exists(videoPath)) {
return ResponseEntity.notFound().build();
}
Resource resource = new FileSystemResource(videoPath);
long fileLength = resource.contentLength();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept-Ranges", "bytes");
headers.set("Content-Disposition", "inline");
// 处理范围请求
if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
String range = rangeHeader.substring(6);
String[] ranges = range.split("-");
long start = Long.parseLong(ranges[0]);
long end = ranges.length > 1 ? Long.parseLong(ranges[1]) : fileLength - 1;
long rangeLength = end - start + 1;
if (rangeLength < 0 || start < 0 || end >= fileLength) {
return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
.header("Content-Range", "bytes */" + fileLength)
.build();
}
headers.set("Content-Range", "bytes " + start + "-" + end + "/" + fileLength);
headers.setContentLength(rangeLength);
// 读取部分内容
InputStreamResource inputStreamResource = createPartialContent(resource, start, rangeLength);
return ResponseEntity.status(HttpStatus.PARTIAL_CONTENT)
.headers(headers)
.contentType(MediaType.parseMediaType("video/mp4"))
.body(inputStreamResource);
}
// 完整文件响应
headers.setContentLength(fileLength);
headers.set("Content-Type", "video/mp4");
headers.set("X-Content-Duration", getVideoDuration(videoPath));
headers.set("Cache-Control", isTranscoded ? "public, max-age=2592000" : "no-cache");
return ResponseEntity.ok()
.headers(headers)
.body(resource);
}
/**
* 创建部分内容资源
*/
private InputStreamResource createPartialContent(Resource resource, long start, long length) throws IOException {
InputStream inputStream = resource.getInputStream();
inputStream.skip(start);
return new InputStreamResource(inputStream) {
@Override
public InputStream getInputStream() throws IOException {
return new LimitedInputStream(inputStream, length);
}
@Override
public long contentLength() throws IOException {
return length;
}
};
}
/**
* 限制输入流
*/
private static class LimitedInputStream extends InputStream {
private final InputStream wrapped;
private long remaining;
public LimitedInputStream(InputStream wrapped, long limit) {
this.wrapped = wrapped;
this.remaining = limit;
}
@Override
public int read() throws IOException {
if (remaining <= 0) return -1;
int result = wrapped.read();
if (result != -1) remaining--;
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (remaining <= 0) return -1;
int toRead = (int) Math.min(len, remaining);
int result = wrapped.read(b, off, toRead);
if (result != -1) remaining -= result;
return result;
}
}
/**
* 获取视频时长
*/
private String getVideoDuration(Path videoPath) throws IOException {
try {
Process proc = new ProcessBuilder(
"ffprobe", "-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
videoPath.toString()
).start();
try (BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()))) {
String duration = br.readLine();
if (duration != null && !duration.trim().isEmpty()) {
return durationFormat.format(Double.parseDouble(duration.trim()));
}
}
} catch (Exception e) {
System.err.println("获取视频时长失败: " + e.getMessage());
}
return "0.00";
}
}

View File

@@ -0,0 +1,73 @@
package com.example.sjkbf.controller;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.sjkbf.config.Configuration.CurrentUserId;
import com.example.sjkbf.entity.CommonResult;
import com.example.sjkbf.service.UserOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.Map;
@RestController()
@RequestMapping("/zf")
public class ZfController {
String payKey = "8658ea66fbbe4a1aad4691ddecefe5fa";
String payUrl = "https://2277883.pay.lanjingzf.com/createOrder?";
@Autowired
private UserOrderService service;
/**
*
* @param payId 商户订单号
* @param param 创建订单的时候传入的参数
* @param type 支付方式 微信支付为1 支付宝支付为2
* @param price 订单金额
* @param reallyPrice 实际支付金额
* @param sign 校验签名,计算方式 = md5(payId + param + type + price + reallyPrice + 通讯密钥)
*/
@RequestMapping("callback")
public String callback(@RequestParam String payId,@RequestParam String param,@RequestParam Integer type, @RequestParam Float price,@RequestParam Float reallyPrice,@RequestParam String sign){
System.out.println(payId);
System.out.println(param);
System.out.println(type);
System.out.println(price);
System.out.println(reallyPrice);
System.out.println(sign);
return service.callback(payId, param, type, price, reallyPrice, sign);
}
@RequestMapping("create")
public ResponseEntity<CommonResult<String>> create(@RequestBody Map<String,Integer> body, @CurrentUserId String userName) throws IOException {
String s = service.create(body.get("type"), body.get("price"), userName);
return ResponseEntity.ok( CommonResult.success(s));
}
public static void main(String[] args) throws InterruptedException, IOException {
UserOrderService service = new UserOrderService();
String s = service.create(1, 1, "123");
System.out.println(s);
}
}

View File

@@ -0,0 +1,729 @@
package com.example.sjkbf.controller;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.common.FileManage;
import com.example.sjkbf.entity.CommonResult;
import com.example.sjkbf.entity.DPSScriptJson;
import com.example.sjkbf.entity.User;
import com.example.sjkbf.entity.UserServerProject;
import com.example.sjkbf.entity.projectconfig.ProjectConfig;
import com.example.sjkbf.service.ProjectPerService;
import com.example.sjkbf.service.UserServerProjectService;
import com.example.sjkbf.service.UserService;
import com.example.sjkbf.service.impl.ProjectPerServiceImpl;
import com.example.sjkbf.util.RSATooL;
import com.example.sjkbf.util.SimpleNutZipCompatible;
import com.example.sjkbf.util.tool;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
@RestController
@RequestMapping("/script")
public class verifyController {
@Autowired
private UserServerProjectService userServerProjectService;
@Autowired
private ProjectPerService projectPerService;
@Autowired
private FileManage fileManage;
@Autowired
private UserService userService;
public static Map<String,String> ipAndMac=new HashMap<>();
@RequestMapping("client")
public ResponseEntity<String> client(String ip,String clientKey,String ve) {
if (ve == null )ve = "1.0";
System.out.println( ve);
StaticLog.info(ip+" client 客户端 请求验证");
List<UserServerProject> getpro=new ArrayList<>();
// if (ip.equals("192.168.200.131")){
// User clientKey1 = userService.getOne(new QueryWrapper<User>().eq("client_key", clientKey));
//
// getpro = userServerProjectService.getByUserName(clientKey1.getName());
//
// }else {
getpro = userServerProjectService.getproAndOpen(ip);
// }
int[] key = new int[20];
StringBuilder keys= new StringBuilder();
for (int i = 0; i < 20; i++) {
key[i]=(RandomUtil.randomInt(1, 9));
keys.append(key[i]);
}
List<String> BaseScriptStr = projectPerService.getBaseScriptStrEncrypt(key,ve);
//如果项目里有cs 就发测试base
for (UserServerProject userServerProject : getpro) {
if (userServerProject.getProjectName().equals("cs")){
BaseScriptStr = projectPerService.getCSBaseScriptStrEncrypt(key,ve);
break;
}
}
if (!getpro.isEmpty()) {
for (UserServerProject userServerProject : getpro) {
String projectName = userServerProject.getProjectName();
if (projectName.equals("cs"))continue;
List<String> projectScriptStrEncrypt = projectPerService.getProjectScriptStrEncrypt(projectName, key,ve);
BaseScriptStr.addAll(projectScriptStrEncrypt);
System.out.println(projectName + " 加载" + projectScriptStrEncrypt.size() + "个文件");
}
}
System.out.println(BaseScriptStr.size());
List<String> projectScriptStrEncrypt = projectPerService.getzdy(ip, key,ve);
if (!projectScriptStrEncrypt.isEmpty()) {
BaseScriptStr.addAll(projectScriptStrEncrypt);
System.out.println("加载自定义脚本" + projectScriptStrEncrypt.size() + "个文件");
}
System.out.println(BaseScriptStr.size());
StringBuilder stringBuilder = new StringBuilder();
for (String s : BaseScriptStr) {
stringBuilder.append(s);
stringBuilder.append("$$$$$");
}
JSONObject json = new JSONObject();
json.set("getBaseScriptStr",stringBuilder.toString());
json.set("key", RSATooL.encryption(keys.toString()));
String string = json.toString();
String compress = RSATooL.compress(string);
return ResponseEntity.ok(compress);
}
@RequestMapping("getzdy")
public String getzdy( HttpServletRequest request,String ve) {
String ipAddress = request.getRemoteAddr();
// 如果应用部署在反向代理或负载均衡器后面可以通过X-Forwarded-For头部获取真实IP地址
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
ipAddress = forwardedFor.split(",")[0];
}
System.out.println(ipAddress + "请求自定义脚本");
List<String> projectScriptStrEncrypt = projectPerService.getzdy2(ipAddress,ve);
if (!projectScriptStrEncrypt.isEmpty()) {
System.out.println("加载自定义脚本" + projectScriptStrEncrypt.size() + "个文件");
}else {
return "";
}
// StringBuilder stringBuilder = new StringBuilder();
// for (String s : projectScriptStrEncrypt) {
//
//
// stringBuilder.append(s);
// stringBuilder.append("$$$$$");
// }
JSONObject json = new JSONObject();
json.set("getBaseScriptStr",projectScriptStrEncrypt);
String string = json.toString();
// String compress = RSATooL.compress(string);//压缩
return string;
}
@RequestMapping("client2")
public ResponseEntity<Map<String, Object>> client2(String ip,String clientKey,String ve) {
System.out.println( ve);
StaticLog.info(ip+"client2 客户端 请求验证");
List<UserServerProject> getpro=new ArrayList<>();
// if (ip.equals("192.168.200.131")){
// User clientKey1 = userService.getOne(new QueryWrapper<User>().eq("client_key", clientKey));
//
// getpro = userServerProjectService.getByUserName(clientKey1.getName());
//
// }else {
getpro = userServerProjectService.getproAndOpen(ip);
// }
int[] key = new int[20];
StringBuilder keys= new StringBuilder();
for (int i = 0; i < 20; i++) {
key[i]=(RandomUtil.randomInt(1, 9));
keys.append(key[i]);
}
List<byte[]> BaseScriptStr = projectPerService.getBaseScriptStrEncrypt2(key,ve);
if (!getpro.isEmpty()) {
for (UserServerProject userServerProject : getpro) {
String projectName = userServerProject.getProjectName();
List<byte[]> projectScriptStrEncrypt = projectPerService.getProjectScriptStrEncrypt2(projectName, key,ve);
BaseScriptStr.addAll(projectScriptStrEncrypt);
System.out.println(projectName + " 加载" + projectScriptStrEncrypt.size() + "个文件");
}
}
Map<String, Object> map = new HashMap<>();
map.put("getBaseScriptStr",BaseScriptStr);
map.put("key",RSATooL.encryption(keys.toString()));
return ResponseEntity.ok(map);
}
/**
* 服务端验证
*/
@PostMapping("getpro")
public String getpro(HttpServletRequest request, String prot, Long l, String mac, String s){
String ipAddress = tool.getIpAddress(request);
long time = DateUtil.date().getTime();
StaticLog.info(ipAddress+"服务端 请求验证");
if (Math.abs(time - l)>1000*60*5||mac==null||mac.isEmpty()||prot==null||prot.isEmpty()){
StaticLog.info(ipAddress+"服务端 请求验证失败");
StaticLog.info(String.valueOf(Math.abs(time - l)>1000*60*5));
StaticLog.info(String.valueOf(mac==null||mac.isEmpty()));
StaticLog.info(String.valueOf(prot==null||prot.isEmpty()));
return null;
}
String s1 = ipAndMac.get(ipAddress);
if (s1==null||s1.isEmpty()){
ipAndMac.put(ipAddress,mac);
s1 = mac;
}
if (!s1.equals(mac)){
//不同的md5值 记录日志
StaticLog.error("md5值和之前不相同 :" + ipAddress);
}
List<UserServerProject> getpro = userServerProjectService.getproAndOpen(ipAddress);
if (getpro.isEmpty()) {
StaticLog.error("验证错误" + ipAddress);
return null;
}
StringBuilder pro = new StringBuilder();
for (UserServerProject userServerProject : getpro) {
pro.append(userServerProject.getProjectName()).append(",");
}
Map<String,Object> body=new HashMap<>();
body.put("pro", pro.toString());
body.put("validate",time);
body.put("ce",s);
//生成一个唯一的id 作为穿给中间件的验证值 存到redis 中
String key = IdUtil.simpleUUID();
body.put("key",key);
body.put("ip",ipAddress);
StaticLog.info(ipAddress+"服务端 通过验证");
String jsonStr = JSONUtil.toJsonStr(body);
return tool.encryption(jsonStr);
}
@RequestMapping("getservice")
public ResponseEntity<String> getservice( HttpServletRequest request,String ser) throws IOException {
StaticLog.info("收到服务器的getservice2请求脚本");
// 获取客户端IP地址
String ipAddress = request.getRemoteAddr();
// 如果应用部署在反向代理或负载均衡器后面可以通过X-Forwarded-For头部获取真实IP地址
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
ipAddress = forwardedFor.split(",")[0];
}
int[] intArray1 = new int[20];
StringBuilder keys= new StringBuilder();
for (int i = 0; i < 20; i++) {
intArray1[i]=(RandomUtil.randomInt(1, 9));
keys.append(intArray1[i]);
}
//项目map
Map<String, byte[]> stringStringMap=new HashMap<>();
List<String> stringStringMapSX=new ArrayList<>();
List<UserServerProject> getpro = userServerProjectService.getproAndOpen(ipAddress);
if (getpro.isEmpty()) {
//把通用的数据线丢到map中
List<String> strings333 = FileUtil.readUtf8Lines(fileManage.getDpsScriptfile()+"base2/config");
for (String s : strings333) {
File file2 = FileUtil.file(fileManage.getDpsScriptfile()+"base2/" + s);
FileReader fileReader1 = new FileReader(fileManage.getDpsScriptfile()+"base2/" + s);
stringStringMap.put(fileManage.getDpsScriptfile()+"base2/" + s, fileReader1.readString().getBytes());
stringStringMapSX.add(fileManage.getDpsScriptfile()+"base2/" + s);
}
System.out.println("通过了 没买插件的验证");
}else {
if (ipAddress .equals("112.12.194.152") || ipAddress .equals("202.189.14.166") || ipAddress .equals("45.125.44.2") || ipAddress .equals("110.42.110.159")|| ipAddress .equals("202.189.14.111")){
//把通用的数据线丢到map中
List<String> strings333 = FileUtil.readUtf8Lines(fileManage.getDpsScriptfile()+"" +
"" +
"base3/config");
for (String s : strings333) {
File file2 = FileUtil.file(fileManage.getDpsScriptfile()+"base3/" + s);
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(fileManage.getDpsScriptfile()+"base3/" + s, fileReader1 .readString().getBytes());
stringStringMapSX.add(fileManage.getDpsScriptfile()+"base3/" + s);
}
}else {
//把通用的数据线丢到map中
List<String> strings333 = FileUtil.readUtf8Lines(fileManage.getDpsScriptfile()+"base/config");
for (String s : strings333) {
File file2 = FileUtil.file(fileManage.getDpsScriptfile()+"base/" + s);
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(fileManage.getDpsScriptfile()+"base/" + s, fileReader1 .readString().getBytes());
stringStringMapSX.add(fileManage.getDpsScriptfile()+"base/" + s);
}
}
//从数据库找到所有的插件
for (UserServerProject user2 : getpro) {
String chajian = user2.getProjectName();
String s1 = fileManage.getDpsScriptfile() + "project/" + chajian;
Path path = Paths.get(s1);
//根据插件获得服务器的插件路径 然后以路径为key 里面的值为v 存入到map中 之后加密返回
if (Files.exists(path)) {
List<String> strings444 = FileUtil.readUtf8Lines(s1 + "/config");
for (String s : strings444) {
File file2 = FileUtil.file(s1 + "/" + s);
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(s1 + "/" + s, fileReader1.readString().getBytes());
stringStringMapSX.add(s1 + "/" + s);
}
}
}
File file2 = FileUtil.file(fileManage.getDpsScriptfile() + "user/通用/main.nut");
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(fileManage.getDpsScriptfile() + "user/通用/main.nut", fileReader1.readString().getBytes());
stringStringMapSX.add(fileManage.getDpsScriptfile() + "user/通用/main.nut");
}
if (ipAddress .equals("112.12.194.152") || ipAddress .equals("202.189.14.166") || ipAddress .equals("45.125.44.2") || ipAddress .equals("110.42.110.159")|| ipAddress .equals("202.189.14.111")){
for (String stringMapSX : stringStringMapSX) {
System.out.println(stringMapSX);
}
}
//以下代码为从/root/rindro/dpsScript/user/ 目录中加载自定义的服务端脚本
String s1 = fileManage.getDpsScriptfile() + "user/" + ipAddress;
Path path = Paths.get(s1);
if (Files.exists(path)) {
List<String> strings444 = FileUtil.readUtf8Lines(s1 + "/config");
for (String s : strings444) {
File file2 = FileUtil.file(s1 + "/" + s);
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(s1 + "/" + s, fileReader1.readString().getBytes());
stringStringMapSX.add(s1 + "/" + s);
}
}
// Map<String, byte[]> stringStringMapUser=new HashMap<>();
// List<String> stringStringMapUserSX=new ArrayList<>();
// try {
// List<String> strings2222 = FileUtil.readUtf8Lines("/root/rindro/user/"+ipAddress + "/serConfig");
//
// for (String s : strings2222) {
// File file2 = FileUtil.file("/root/rindro/user/"+ipAddress + "/"+s);
// FileReader fileReader = new FileReader(file2);
// byte[] bytes = fileReader.readBytes();
// stringStringMapUser.put("/root/rindro/user/"+ipAddress + "/"+s,bytes);
// stringStringMapUserSX.add("/root/rindro/user/"+ipAddress + "/"+s);
// }
// }catch (Exception e){
// System.out.println("未找到userip文件外部用户请求");
// }
// 对通用文件进行加密处理
for (Map.Entry<String, byte[]> entry : stringStringMap.entrySet()) {
byte[] encryptedValue = RSATooL.Makecode(entry.getValue(), intArray1);
entry.setValue(encryptedValue); // 直接在Map中更新值
}
// //对用户文件进行加密处理
// for (Map.Entry<String, byte[]> entry : stringStringMapUser.entrySet()) {
// byte[] encryptedValue = Main.Makecode(entry.getValue(), intArray1);
// entry.setValue(encryptedValue); // 直接在Map中更新值
// }
StringBuilder sb=new StringBuilder();
for (String string : stringStringMapSX) {
sb.append(string);
sb.append("$$$$$");
String string1 = Arrays.toString(stringStringMap.get(string));
sb.append(string1, 1, string1.length()-1);
sb.append("$$$$$");
}
// for (String string : stringStringMapUserSX) {
// sb.append(string);
// sb.append("$$$$");
// sb.append(Arrays.toString(stringStringMapUser.get(string)));
// sb.append("$$$$");
// }
String substring = sb.toString();
StaticLog.info(ipAddress+"通过验证 返回dps nut脚本");
JSONObject json = new JSONObject();
json.set("getBaseScriptStr",substring);
json.set("key",RSATooL.encryption(keys.toString()));
String string = json.toString();
String compress = RSATooL.compress(string);
return ResponseEntity.ok(compress);
}
Map<String,JSONObject> jsonObject=new HashMap<>();
@RequestMapping ("getBaseUpdateTime")
public ResponseEntity<String> getBaseUpdateTime(String ve) {
if (ve == null) ve = "1.0";
// 1. 构建 base 目录路径(避免硬编码拼接,用 File 构造方法更安全)
String baseDirPath = fileManage.getFile() + "/DP-S_Script/Script"+ve+"/_DPS_";
File baseDir = new File(baseDirPath);
// 2. 校验目录合法性(不存在/不是目录直接返回 0
if (!baseDir.exists() || !baseDir.isDirectory()) {
return ResponseEntity.ok("0");
}
// 3. 递归遍历所有文件,获取最新修改时间
long latestModifyTime = traverseAllFiles(baseDir);
// 4. 返回结果(时间戳转字符串)
return ResponseEntity.ok(String.valueOf(latestModifyTime));
}
@RequestMapping("getBaseSutZip")
public ResponseEntity<Object> getBaseSut(HttpServletRequest request,@RequestParam(value = "ve", required = false) String ve) {
nut_sut(ve);
String file = fileManage.getFile() +"sut.tar.gz";
Path baseDir = Paths.get(file).toAbsolutePath().normalize();
Resource resource = new FileSystemResource(baseDir);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"");
// 返回包含文件资源的通用结果
return ResponseEntity.ok()
.header("Content-Disposition",
"attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
}
Map<String,Long> updateTime=new HashMap<>();
public void nut_sut(String bb) {
if (bb ==null) bb = "1.0";
String baseDirPath = fileManage.getFile() + "/DP-S_Script/Script"+bb+"/_DPS_";
File baseDir = new File(baseDirPath);
long latestModifyTime = traverseAllFiles(baseDir);
System.out.println("最新修改时间:" + latestModifyTime);
System.out.println("updateTime" + updateTime.get(bb));
if ( updateTime.get(bb) == null || latestModifyTime > updateTime.get(bb)){
//重新加密压缩
String targetPath = fileManage.getFile()+"sut.tar.gz";
String key = "Rindro-Aurora";
SimpleNutZipCompatible.encryptAndZip(baseDirPath, targetPath, key);
updateTime.put(bb,traverseAllFiles(baseDir));
FileReader fileReader = new FileReader(fileManage.getFile() + "/DP-S_Script/Script"+bb+"/_DPS_" + "/FileConfig.json");
String result5 = fileReader.readString();
//转json
JSONObject jsonObject1 = new JSONObject(result5);
jsonObject.put(bb,jsonObject1);
}
}
@RequestMapping("getservicenew")
public ResponseEntity<String> getservicenew( HttpServletRequest request,String ser,String ve) throws IOException {
if (ve == null ){
ve = request.getHeader("ve");
if ( ve == null) {
StaticLog.info("版本 为空");
ve = "1.0";
}
}
// 获取客户端IP地址
String ipAddress = request.getRemoteAddr();
// 如果应用部署在反向代理或负载均衡器后面可以通过X-Forwarded-For头部获取真实IP地址
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
ipAddress = forwardedFor.split(",")[0];
}
StaticLog.info("收到服务器"+ipAddress+" 的getservicenew请求脚本 当前版本" + ve);
int[] intArray1 = new int[20];
StringBuilder keys= new StringBuilder();
for (int i = 0; i < 20; i++) {
intArray1[i]=(RandomUtil.randomInt(1, 9));
keys.append(intArray1[i]);
}
//项目map
Map<String, byte[]> stringStringMap=new HashMap<>();
List<String> stringStringMapSX=new ArrayList<>();
List<UserServerProject> getpro = userServerProjectService.getproAndOpen(ipAddress);
if (getpro.isEmpty()) {
return ResponseEntity.ok("没有项目");
}else {
//从数据库找到所有的插件
for (UserServerProject user2 : getpro) {
String chajian = user2.getProjectName();
if (jsonObject.get(ve) ==null){
nut_sut(ve);
System.out.println(jsonObject.get(ve));
}
DPSScriptJson bean = jsonObject.get(ve).toBean(DPSScriptJson.class);
DPSScriptJson.ProjectScriptItem projectScriptItem = bean.getProjectScript().get(chajian);
if (projectScriptItem == null) {
StaticLog.info("版本" + ve);
StaticLog.info("没有项目" + chajian);
continue;
}
for (String s : projectScriptItem.getScript()) {
String s1 = fileManage.getFile() + "/DP-S_Script/Script"+ve+"/_DPS_" + "/_BuiltProject/" + s;
File file2 = FileUtil.file(s1 );
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(s1 , fileReader1.readString().getBytes());
stringStringMapSX.add(s1 );
}
StaticLog.info("加入" +chajian +"插件");
}
// File file2 = FileUtil.file(fileManage.getDpsScriptfile() + "user/通用/main.nut");
// FileReader fileReader1 = new FileReader(file2);
// stringStringMap.put(fileManage.getDpsScriptfile() + "user/通用/main.nut", fileReader1.readString().getBytes());
// stringStringMapSX.add(fileManage.getDpsScriptfile() + "user/通用/main.nut");
}
//以下代码为从/root/rindro/dpsScript/user/ 目录中加载自定义的服务端脚本
String s1 = fileManage.getDpsScriptfile() + "user/" + ipAddress;
Path path = Paths.get(s1);
if (Files.exists(path)) {
List<String> strings444 = FileUtil.readUtf8Lines(s1 + "/config");
for (String s : strings444) {
File file2 = FileUtil.file(s1 + "/" + s);
FileReader fileReader1 = new FileReader(file2);
stringStringMap.put(s1 + "/" + s, fileReader1.readString().getBytes());
stringStringMapSX.add(s1 + "/" + s);
}
}
// 对通用文件进行加密处理
for (Map.Entry<String, byte[]> entry : stringStringMap.entrySet()) {
byte[] encryptedValue = RSATooL.Makecode(entry.getValue(), intArray1);
entry.setValue(encryptedValue); // 直接在Map中更新值
}
StringBuilder sb=new StringBuilder();
for (String string : stringStringMapSX) {
sb.append(string);
sb.append("$$$$$");
String string1 = Arrays.toString(stringStringMap.get(string));
sb.append(string1, 1, string1.length()-1);
sb.append("$$$$$");
}
String substring = sb.toString();
StaticLog.info(ipAddress+"通过验证 返回dps nut脚本");
JSONObject json = new JSONObject();
json.set("getBaseScriptStr",substring);
json.set("key",RSATooL.encryption(keys.toString()));
String string = json.toString();
String compress = RSATooL.compress(string);
return ResponseEntity.ok(compress);
}
/**
* 递归遍历目录下所有文件(含所有层级子目录),返回最新修改时间
* @param dir 要遍历的目录
* @return 最新文件修改时间(毫秒级时间戳),无文件时返回 0
*/
private long traverseAllFiles(File dir) {
long latestTime = 0;
// 用原生 listFiles() 替代 FileUtil.ls减少第三方依赖同时处理 null 情况
File[] files = dir.listFiles();
if (files == null) {
return latestTime; // 目录无权限访问或异常,返回当前最新时间
}
for (File file : files) {
if (file.isDirectory()) {
// 递归遍历子目录
latestTime = Math.max(latestTime, traverseAllFiles(file));
} else {
// 对比文件修改时间,更新最新时间
latestTime = Math.max(latestTime, file.lastModified());
}
}
return latestTime;
}
public static void main(String[] args) {
// String decompress = RSATooL.encryption("https://dps-ma.senzo.online");
// System.out.println(decompress);
System.out.println((3860+1730 -150-180-240-(40+37+94+20)) *0.7) ;
System.out.println(3380 -100 -381-850-60-50-100-400-100-40-150-250-175 -100);
}
}

View File

@@ -0,0 +1,16 @@
package com.example.sjkbf.entity;
import lombok.Getter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
@Getter
public class AuthUser extends User {
private final Integer userId;
public AuthUser(Integer userId, String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
this.userId = userId;
}
}

View File

@@ -0,0 +1,118 @@
package com.example.sjkbf.entity;
import com.baomidou.mybatisplus.extension.api.IErrorCode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T> {
// 状态码
private Integer code;
// 提示信息
private String message;
// 返回的数据
private T data;
/**
* 成功返回结果
*
* @param data 返回的数据
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> success(T data) {
return new CommonResult<>(200, "操作成功", data);
}
/**
* 成功返回结果并自定义提示信息
*
* @param data 返回的数据
* @param message 提示信息
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> success(T data, String message) {
return new CommonResult<>(200, message, data);
}
/**
* 失败返回结果并自定义提示信息
*
* @param message 提示信息
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> failed(String message) {
return new CommonResult<>(500, message, null);
}
/**
* 失败返回结果
*
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> failed() {
return failed(500, "操作失败");
}
/**
* 失败返回结果
*
* @param code 错误码
* @param message 提示信息
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> failed(int code, String message) {
return new CommonResult<>(code, message, null);
}
/**
* 参数验证失败返回结果
*
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> validateFailed() {
return failed(400, "参数验证失败");
}
/**
* 参数验证失败返回结果并自定义提示信息
*
* @param message 提示信息
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> validateFailed(String message) {
return failed(400, message);
}
/**
* 未登录返回结果
*
* @param data 返回的数据
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> unauthorized(T data) {
return new CommonResult<>(401, "暂未登录或 token 已经过期", data);
}
/**
* 未授权返回结果
*
* @param data 返回的数据
* @param <T> 数据类型
* @return 通用返回对象
*/
public static <T> CommonResult<T> forbidden(T data) {
return new CommonResult<>(403, "没有相关权限", data);
}
}

View File

@@ -0,0 +1,21 @@
package com.example.sjkbf.entity;
import lombok.Data;
import lombok.Getter;
import java.util.List;
import java.util.Map;
@Data
public class DPSScriptJson {
private List<String> BaseScript;
private Map<String, ProjectScriptItem> ProjectScript;
@Data
public static class ProjectScriptItem {
private List<String> Script;
}
}

View File

@@ -0,0 +1,16 @@
package com.example.sjkbf.entity.DTO;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class LoginRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@NotBlank(message = "密码不能为空")
private String password;
@NotBlank(message = "验证qq不能为空")
private String qq;
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.entity.DTO;
import lombok.Data;
import java.util.List;
@Data
public class LoginResponse {
private String token;
private String username;
private List<String> roles; // 权限/角色列表
public LoginResponse(String token, String username, List<String> roles) {
this.token = token;
this.username = username;
this.roles = roles;
}
}

View File

@@ -0,0 +1,34 @@
package com.example.sjkbf.entity;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author bozhiqiang
* @since 2025-09-25
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Log implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String log;
private Integer type;
//时间
private Date time;
}

View File

@@ -0,0 +1,31 @@
package com.example.sjkbf.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectPer implements Serializable {
private static final long serialVersionUID = 1L;
@TableId
private String projectName;
private String file;
private Integer permission;
private Integer demandGold;
}

View File

@@ -0,0 +1,51 @@
package com.example.sjkbf.entity;
import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
private Integer id;
private String username;
private String password;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
private Integer gold;
private String qq;
private String name;
private String img;
private String clientKey;
private String serverKey;
}

View File

@@ -0,0 +1,33 @@
package com.example.sjkbf.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author bozhiqiang
* @since 2025-04-17
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UserAndServer implements Serializable {
private static final long serialVersionUID = 1L;
private String userName;
private String serverIp;
private String account;
private String password;
private String port;
}

View File

@@ -0,0 +1,33 @@
package com.example.sjkbf.entity;
import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author bozhiqiang
* @since 2025-04-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UserServerProject implements Serializable {
private static final long serialVersionUID = 1L;
private String serverIp;
private String projectName;
private Date expirationDate;
private String userName;
private int open;
}

View File

@@ -0,0 +1,31 @@
package com.example.sjkbf.entity.projectconfig;
import lombok.Data;
import java.util.List;
import java.util.Map;
@Data
public class Project {
String name;
List<String> Script;
Map<String,Object> Info;
/**
* 价格
*/
Integer price;
/**
* 是否私有
*/
Boolean Private = false;
/**
* img路径
*/
String imgPath;
}

View File

@@ -0,0 +1,26 @@
package com.example.sjkbf.entity.projectconfig;
import lombok.Data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
public class ProjectConfig {
private List<String> BaseScript;
private List<String> CSBaseScript;
private Map<String, Project> ProjectScript = new HashMap<>();
public List<String> BaseScriptStr = new ArrayList<>();
public List<String> CSBaseScriptStr = new ArrayList<>();
public Map<String, List<String>> ProjectScriptStr = new HashMap<>();
//自定义脚本 key为ip v为自定义脚本
public Map<String, List<String>> ProjectZDYScriptStr = new HashMap<>();
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.sjkbf.entity.Log;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author bozhiqiang
* @since 2025-09-25
*/
@Mapper
public interface LogMapper extends BaseMapper<Log> {
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.mapper;
import com.example.sjkbf.entity.ProjectPer;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Mapper()
public interface ProjectPerMapper extends BaseMapper<ProjectPer> {
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.mapper;
import com.example.sjkbf.entity.UserAndServer;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author bozhiqiang
* @since 2025-04-17
*/
@Mapper
public interface UserAndServerMapper extends BaseMapper<UserAndServer> {
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.mapper;
import com.example.sjkbf.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

View File

@@ -0,0 +1,18 @@
package com.example.sjkbf.mapper;
import com.example.sjkbf.entity.UserServerProject;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author bozhiqiang
* @since 2025-04-19
*/
@Mapper
public interface UserServerProjectMapper extends BaseMapper<UserServerProject> {
}

View File

@@ -0,0 +1,16 @@
package com.example.sjkbf.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.sjkbf.entity.Log;
/**
* <p>
* 服务类
* </p>
*
* @author bozhiqiang
* @since 2025-09-25
*/
public interface LogService extends IService<Log> {
}

View File

@@ -0,0 +1,86 @@
package com.example.sjkbf.service;
import com.example.sjkbf.entity.ProjectPer;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.sjkbf.entity.projectconfig.Project;
import com.example.sjkbf.entity.projectconfig.ProjectConfig;
import java.util.List;
import java.util.Map;
/**
* <p>
* 服务类
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
public interface ProjectPerService extends IService<ProjectPer> {
/**
* 根据项目名字获得项目信息
* @param projectName
* @return
*/
Project getByName(String projectName);
/**
* 获得公开的插件项目信息
* @return
*/
Map<String, Map<String, Object>> getProjectInfoList();
/**
* 获得全部的插件项目信息
* @return
*/
Map<String, Map<String, Object>> getProjectInfoListAll();
List<String> getBaseScriptStr( String ve);
/**
* 获得base加密后的脚本
* @param key
* @return
*/
List<String> getBaseScriptStrEncrypt(int[] key,String ve);
List<String> getCSBaseScriptStrEncrypt(int[] key,String ve);
List<String> getProjectScriptStr(String projectName,String ve);
/**
* 获得项目加密后的脚本
* @param projectName
* @param key
* @return
*/
List<String> getProjectScriptStrEncrypt(String projectName,int[] key,String ve);
List<byte[]> getProjectScriptStrEncrypt2(String projectName,int[] key,String ve);
/**
* 获得项目购买所需积分
* @param projectName
* @return
*/
int getProjectPrice(String projectName);
List<byte[]> getBaseScriptStrEncrypt2(int[] key,String ve);
/**
* 获得自定义脚本
* @param ip
* @param key
* @return
*/
List<String> getzdy(String ip, int[] key,String ve);
/**
* 获得没加密的自定义脚本
* @param ip
* @param ve
* @return
*/
List<String> getzdy2(String ip,String ve);
}

View File

@@ -0,0 +1,25 @@
package com.example.sjkbf.service;
import com.example.sjkbf.entity.UserAndServer;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 用户的服务器 服务类
* </p>
*
* @author bozhiqiang
* @since 2025-04-17
*/
public interface UserAndServerService extends IService<UserAndServer> {
int selectCount(String ip, String userName);
List<UserAndServer> getServerList(String userName);
String updateServer(String ip, String userName, String account, String password, String port);
}

View File

@@ -0,0 +1,174 @@
package com.example.sjkbf.service;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.example.sjkbf.util.MD5;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @Author l'amour solitaire
* @Description 订单服务相关
* @Date 2022/12/1 下午5:24
**/
@Slf4j
@Service
public class UserOrderService {
@Autowired
private UserService userService;
private final String payKey = "8658ea66fbbe4a1aad4691ddecefe5fa";
private final String payUrl = "https://2277883.pay.lanjingzf.com/createOrder?";
private static final String CREATE_PARAMS = "payId=%s&type=%s&price=%s&sign=%s&isHtml=1";
public static TimedCache<String, Integer> timedCache = CacheUtil.newTimedCache(3000);
Map<String, Integer> orderIdAndPrice=new HashMap<>();
static {
timedCache.schedulePrune(100);
}
/**
* @param payType 【必传】微信支付传入1 支付宝支付传入2
* @param price 【必传】订单金额
* @Author l'amour solitaire
* @Description 创建订单
* @Date 2022/12/1 下午5:46
**/
public String create(Integer payType, int price,String name) throws IOException {
Integer i = timedCache.get(name);
if (i==null) {
timedCache.put(name, 1,5*60*1000);
}else {
return "上次提交暂未结束,请稍后重试";
}
// 创建订单 订单号为uid:时间戳
String orderId = name + ":" + System.currentTimeMillis();
orderIdAndPrice.put(orderId,price);
String CREATE_PARAMS = "payId=%s&type=%d&price=%s&sign=%s&isHtml=1";
String signSource = orderId + payType + price + payKey;
String sign = DigestUtil.md5Hex(signSource);
String paramMap = String.format(CREATE_PARAMS, orderId, payType, price, sign);
HttpResponse execute = HttpRequest.get(payUrl+paramMap)
// .header(Header.USER_AGENT, "Hutool http")//头信息,多个头信息多次调用此方法即可
.timeout(20000)//超时,毫秒
.execute();
String body = execute.body();
// 返回支付页面地址,前端进行弹框展示即可
return "https://2277883.pay.lanjingzf.com/"+extractBetweenQuotes(body);
}
/**
* 支付回调
**/
public String callback(String payId, String param, int type, double price, double reallyPrice, String sign) {
Assert.isTrue(sign.equals(DigestUtil.md5Hex(payId + param + type + price + reallyPrice + payKey)), "非法请求!");
System.out.println(payId);
Integer i = orderIdAndPrice.get(payId);
System.out.println(orderIdAndPrice);
if (i==null) {
log.info("订单不存在");
return "订单不存在";
}
if (i==-1){
log.info("订单已处理");
return "订单已处理";
}
String[] split = payId.split(":");
userService.addgold(split[0],i);
log.info("订单支付成功");
timedCache.remove(split[0]);
orderIdAndPrice.put(payId,-1);
// 返回这个字符串,支付平台就知道回调接口成功了
return "success";
}
public static String extractBetweenQuotes(String input) {
// 检查输入是否为null
if (input == null) {
return null;
}
// 找到第一个单引号的位置
int firstQuoteIndex = input.indexOf('\'');
// 找到第二个单引号的位置(从第一个引号之后开始查找)
int secondQuoteIndex = input.indexOf('\'', firstQuoteIndex + 1);
// 检查两个引号是否都存在且位置有效
if (firstQuoteIndex != -1 && secondQuoteIndex != -1 && secondQuoteIndex > firstQuoteIndex) {
// 提取两个引号之间的子字符串
return input.substring(firstQuoteIndex + 1, secondQuoteIndex);
}
// 如果未找到有效的引号对返回null
return null;
}
public static void main(String[] args) {
int 毛收入=1890 +1381 +60+100+80+380 -50-30;//支付宝加微信加dps端收入
int 净收入 = 毛收入 -245-20;//扣除服务器费用和会员费
int 董收入= (int) (净收入*0.7);
int 扣除dps端已经付给董的费用 = 董收入 -(60+100+80+380);
int 最终结果 = 扣除dps端已经付给董的费用 - (1220 +100+ 3600 +95 +50); //1220为上月遗留 3600为贪玩账单 剩下的吃饭
System.out.println(最终结果);
}
}

View File

@@ -0,0 +1,57 @@
package com.example.sjkbf.service;
import com.example.sjkbf.entity.UserServerProject;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 用户服务器插件 服务类
* </p>
*
* @author bozhiqiang
* @since 2025-04-19
*/
public interface UserServerProjectService extends IService<UserServerProject> {
/**
* 给服务器添加或延长插件时间
* @param ip 服务器ip
* @param projectName 插件名字
* @param time 时间
* @param userName 用户名
*/
void addpro(String ip,String projectName,int time,String userName);
/**
* 查询此服务器下的插件列表
*/
List<UserServerProject> getpro(String ip);
/**
* 查询这个服务器下开启的插件列表
* @param ip
* @return
*/
List<UserServerProject> getproAndOpen(String ip);
/**
* 查询这个服务器下的插件
* @param serverIp
* @param projectName
* @return
*/
UserServerProject getByIPAndName(String serverIp, String projectName);
/**
* 查询这个账号下的所有插件
*/
List<UserServerProject> getByUserName(String userName);
String setproOpen(String ip, String projectName, String open, String userName);
}

View File

@@ -0,0 +1,33 @@
package com.example.sjkbf.service;
import com.example.sjkbf.entity.DTO.LoginRequest;
import com.example.sjkbf.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 用户 服务类
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
public interface UserService extends IService<User> {
public boolean isUsernameExist(String username);
public void registerUser(LoginRequest request);
String buy(String ip, String projectName, String userName);
void updatePassword(LoginRequest request);
String addServer(String ip, String userName, String account, String password, String port);
String deleteServer(String ip, String userName);
String setKey(String userName, String clientkey, String serverkey);
String addgold(String userName, Integer gold);
String transfer(String myName, String username, Integer gold);
}

View File

@@ -0,0 +1,21 @@
package com.example.sjkbf.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.sjkbf.mapper.LogMapper;
import com.example.sjkbf.service.LogService;
import com.example.sjkbf.entity.Log;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author bozhiqiang
* @since 2025-09-25
*/
@Service
public class LogServiceImpl extends ServiceImpl<LogMapper, Log> implements LogService {
}

View File

@@ -0,0 +1,388 @@
package com.example.sjkbf.service.impl;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.sjkbf.common.FileManage;
import com.example.sjkbf.entity.ProjectPer;
import com.example.sjkbf.entity.projectconfig.Project;
import com.example.sjkbf.entity.projectconfig.ProjectConfig;
import com.example.sjkbf.mapper.ProjectPerMapper;
import com.example.sjkbf.service.ProjectPerService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.sjkbf.util.RSATooL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>
* 服务实现类
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Service
public class ProjectPerServiceImpl extends ServiceImpl<ProjectPerMapper, ProjectPer> implements ProjectPerService {
@Autowired
FileManage fileManage;
// public ProjectConfig projectConfig;
//key为文件夹名字 y为json
Map<String, ProjectConfig> projectScriptMap;
public String configMd5="";
@Override
public Project getByName(String projectName) {
if (projectName != null){
return projectScriptMap.get("max").getProjectScript().get(projectName);
}
return null;
}
@Override
public Map<String, Map<String, Object>> getProjectInfoList() {
Map<String, Project> projectScript = projectScriptMap.get("max").getProjectScript();
Set<String> strings = projectScript.keySet();
Map<String, Map<String, Object>> info = new HashMap<>();
for (String string : strings) {
//如果是私有的就不放进去
if(projectScript.get(string).getPrivate())continue;
Map<String, Object> info1 = projectScript.get(string).getInfo();
info1.put("ProjectPrice", projectScript.get(string).getPrice());
info.put(string, info1);
}
return info;
}
@Override
public Map<String, Map<String, Object>> getProjectInfoListAll() {
Map<String, Project> projectScript = projectScriptMap.get("max").getProjectScript();
Set<String> strings = projectScript.keySet();
Map<String, Map<String, Object>> info = new HashMap<>();
for (String string : strings) {
Map<String, Object> info1 = projectScript.get(string).getInfo();
info1.put("ProjectPrice", projectScript.get(string).getPrice());
info.put(string, info1);
}
return info;
}
/**
* 获得所有的base脚本
* 需要一个版本号
* @return
*/
@Override
public List<String> getBaseScriptStr(String ve) {
return projectScriptMap.get(ve).getBaseScriptStr();
}
public List<String> getCSBaseScriptStr(String ve) {
return projectScriptMap.get(ve).getCSBaseScriptStr();
}
/**
* 根据key对base脚本进行加密
* @param key
* @return
*/
@Override
public List<String> getBaseScriptStrEncrypt(int[] key,String ve) {
List<String> baseScriptStr = getBaseScriptStr(ve);
List<String> StrEncrypt = new ArrayList<>();
for (String s : baseScriptStr) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(string.substring(1, string.length()-1));
}
return StrEncrypt;
}
@Override
public List<String> getCSBaseScriptStrEncrypt(int[] key,String ve) {
List<String> baseScriptStr = getCSBaseScriptStr(ve);
List<String> StrEncrypt = new ArrayList<>();
for (String s : baseScriptStr) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(string.substring(1, string.length()-1));
}
return StrEncrypt;
}
/**
* 根据key对base脚本进行加密
*
* @param key
* @return
*/
public List<byte[]> getBaseScriptStrEncrypt2(int[] key,String ve) {
List<String> baseScriptStr = getBaseScriptStr(ve);
List<byte[]> StrEncrypt = new ArrayList<>();
for (String s : baseScriptStr) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(makecode);
}
return StrEncrypt;
}
@Override
public List<String> getzdy(String ip, int[] key,String ve) {
Map<String, List<String>> projectScriptStr = projectScriptMap.get(ve).getProjectZDYScriptStr();
if (projectScriptStr==null)return new ArrayList<>();
List<String> strings = projectScriptStr.get(ip);
if (strings==null)return new ArrayList<>();
List<String> StrEncrypt = new ArrayList<>();
for (String s : strings) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(string.substring(1, string.length()-1));
}
return StrEncrypt;
}
byte[] AESkey = new byte[]{120, -2, 20, -80, -24, 60, 62, -48, -18, 101, -117, -8, 52, 48, -59, 94};
SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, AESkey);
@Override
public List<String> getzdy2(String ip,String ve) {
ve = "max";
Map<String, List<String>> projectScriptStr = projectScriptMap.get(ve).getProjectZDYScriptStr();
if (projectScriptStr==null)return new ArrayList<>();
List<String> strings = projectScriptStr.get(ip);
if (strings==null)return new ArrayList<>();
List<String> StrEncrypt = new ArrayList<>();
for (String s : strings) {
//加密为16进制表示
String encryptHex = aes.encryptHex(s);
StrEncrypt.add(encryptHex);
}
return StrEncrypt;
}
@Override
public List<String> getProjectScriptStr(String projectName,String ve) {
List<String> strings = projectScriptMap.get(ve).getProjectScriptStr().get(projectName);
return strings;
}
@Override
public List<String> getProjectScriptStrEncrypt(String projectName,int[] key,String ve) {
Map<String, List<String>> projectScriptStr = projectScriptMap.get(ve).getProjectScriptStr();
if (projectScriptStr==null)return new ArrayList<>();
List<String> strings = projectScriptStr.get(projectName);
List<String> StrEncrypt = new ArrayList<>();
for (String s : strings) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(string.substring(1, string.length()-1));
}
return StrEncrypt;
}
@Override
public List<byte[]> getProjectScriptStrEncrypt2(String projectName,int[] key,String ve) {
Map<String, List<String>> projectScriptStr = projectScriptMap.get(ve).getProjectScriptStr();
if (projectScriptStr==null)return new ArrayList<>();
List<String> strings = projectScriptStr.get(projectName);
List<byte[]> StrEncrypt = new ArrayList<>();
for (String s : strings) {
byte[] makecode = RSATooL.Makecode(s.getBytes(), key);
String string = Arrays.toString(makecode);
StrEncrypt.add(makecode);
}
return StrEncrypt;
}
@Override
public int getProjectPrice(String projectName) {
if (projectScriptMap.get("max").getProjectScript().get(projectName)!=null){
return projectScriptMap.get("max").getProjectScript().get(projectName).getPrice();
}
return 0;
}
public synchronized void initInfo(){
projectScriptMap = new HashMap<>();
System.out.println("初始化项目信息");
String scriptfile = fileManage.getScriptfile();
//获得这个文件夹下的所有子文件夹
File[] files = FileUtil.ls(scriptfile);
File[] subDirs = Arrays.stream(files)
.filter(File::isDirectory) // 仅保留子文件夹
.toArray(File[]::new);
// 2. 使用自定义自然排序比较器排序
Arrays.sort(subDirs, new NaturalNameComparator());
for (File file : subDirs) {
//取Script 之后的文件名
String name = file.getName().substring(7);
System.out.println( name);
ProjectConfig projectConfig = initInfo(file.getPath());
projectScriptMap.put(name, projectConfig);
projectScriptMap.put("max", projectConfig);
}
}
public static void main(String[] args) {
String content = "test中文";
}
//读取文件
public synchronized ProjectConfig initInfo( String path) {
FileReader fileReader = new FileReader(path+"/"+"FileConfig.json");
String result = fileReader.readString();
ProjectConfig projectConfig = JSONUtil.toBean(result, new TypeReference<ProjectConfig>() {}, true);
List<String> baseScript = projectConfig.getBaseScript();
for (String s : baseScript) {
FileReader fileReader1 = new FileReader(path+"/"+s);
projectConfig.getBaseScriptStr().add(fileReader1.readString());
}
/*
List<String> csBaseScript = projectConfig.getCSBaseScript();
for (String s : csBaseScript) {
FileReader fileReader1 = new FileReader(path+"/"+s);
projectConfig.getCSBaseScriptStr().add(fileReader1.readString());
}*/
Set<String> strings = projectConfig.getProjectScript().keySet();
for (String string : strings) {
List<String> script = projectConfig.getProjectScript().get(string).getScript();
projectConfig.getProjectScriptStr().put(string,new ArrayList<>());
for (String s : script) {
FileReader fileReader1 = new FileReader(path+"\\"+s);
projectConfig.getProjectScriptStr().get(string).add(fileReader1.readString());
}
}
File[] ls = FileUtil.ls("/root/rindro/ClentUserScript");
for (File l : ls) {
Path path1 = Paths.get(l.getPath());
List<String> ZDYScript = new ArrayList<>();
if (Files.exists(path1)) {
List<String> strings444 = FileUtil.readUtf8Lines(l + "/config");
for (String s : strings444) {
File file2 = FileUtil.file(l + "/" + s);
FileReader fileReader1 = new FileReader(file2);
ZDYScript.add(fileReader1.readString());
}
}
projectConfig.getProjectZDYScriptStr().put(l.getName(),ZDYScript);
}
return projectConfig;
}
private static final Pattern NUMBER_PATTERN = Pattern.compile("(\\d+\\.?\\d*)|([^\\d]+)");
// 自定义自然排序比较器(核心)
static class NaturalNameComparator implements Comparator<File> {
@Override
public int compare(File f1, File f2) {
String name1 = f1.getName();
String name2 = f2.getName();
// 拆分两个名称的数字/非数字片段,逐个比较
Matcher m1 = NUMBER_PATTERN.matcher(name1);
Matcher m2 = NUMBER_PATTERN.matcher(name2);
while (m1.find() && m2.find()) {
String segment1 = m1.group();
String segment2 = m2.group();
int compareResult;
// 判断当前片段是否是数字
if (segment1.matches("\\d+\\.?\\d*") && segment2.matches("\\d+\\.?\\d*")) {
// 数字片段:按数值大小比较(支持小数)
double num1 = Double.parseDouble(segment1);
double num2 = Double.parseDouble(segment2);
compareResult = Double.compare(num1, num2);
} else {
// 非数字片段:按字符串字典序比较(忽略大小写,可选)
compareResult = segment1.compareToIgnoreCase(segment2);
}
// 只要有一个片段比较出结果,就返回
if (compareResult != 0) {
return compareResult;
}
}
// 前面的片段都相同,短名称排前面
return Integer.compare(name1.length(), name2.length());
}
}
}

View File

@@ -0,0 +1,58 @@
package com.example.sjkbf.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.entity.UserAndServer;
import com.example.sjkbf.mapper.UserAndServerMapper;
import com.example.sjkbf.service.UserAndServerService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author bozhiqiang
* @since 2025-04-17
*/
@Service
public class UserAndServerServiceImpl extends ServiceImpl<UserAndServerMapper, UserAndServer> implements UserAndServerService {
@Autowired
private UserAndServerMapper userAndServerMapper;
@Override
public int selectCount(String ip, String userName) {
return userAndServerMapper.selectCount(new QueryWrapper<UserAndServer>().eq("server_ip",ip).eq("user_name",userName));
}
@Override
public List<UserAndServer> getServerList(String userName) {
List<UserAndServer> userName1 = list(new QueryWrapper<UserAndServer>().eq("user_name", userName));
return userName1;
}
@Override
public String updateServer(String ip, String userName, String account, String password, String port) {
UserAndServer one = getOne(new QueryWrapper<UserAndServer>().eq("server_ip", ip).eq("user_name", userName));
if (one != null){
one.setAccount(account);
one.setPassword(password);
one.setPort(port);
return updateById(one)?"修改成功":"修改失败";
}
return "服务器不存在";
}
}

View File

@@ -0,0 +1,51 @@
package com.example.sjkbf.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.entity.AuthUser;
import com.example.sjkbf.entity.User;
import com.example.sjkbf.mapper.UserMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
*用户认证类
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserMapper userMapper;
// 构造器注入(推荐)
public UserDetailsServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = null;
try {
// 1. 查询数据库
user= userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
}catch (Exception e){
e.printStackTrace();
}
// 2. 用户不存在
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
// 3. 转换为 Spring Security 的 UserDetails 对象
return new AuthUser(
user.getId(),
user.getUsername(),
user.getPassword(),
AuthorityUtils.createAuthorityList("ROLE_ALL") // 假设 roles 字段存储如 "ROLE_ADMIN,ROLE_USER"
);
}
}

View File

@@ -0,0 +1,93 @@
package com.example.sjkbf.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.entity.UserServerProject;
import com.example.sjkbf.mapper.UserServerProjectMapper;
import com.example.sjkbf.service.UserServerProjectService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author bozhiqiang
* @since 2025-04-19
*/
@Service
public class UserServerProjectServiceImpl extends ServiceImpl<UserServerProjectMapper, UserServerProject> implements UserServerProjectService {
@Override
public void addpro(String ip, String name, int time, String userName) {
UserServerProject one = getOne(new QueryWrapper<UserServerProject>().eq("server_ip", ip).eq("project_name", name));
if (one==null){
UserServerProject userServerProject = new UserServerProject();
userServerProject.setServerIp(ip);
userServerProject.setProjectName(name);
userServerProject.setUserName(userName);
userServerProject.setOpen(1);
DateTime date = DateUtil.date();
DateTime newDate2 = DateUtil.offsetDay(date, time);
userServerProject.setExpirationDate(newDate2);
save(userServerProject);
}else {
Date expirationDate = one.getExpirationDate();
DateTime newDate2 = DateUtil.offsetDay(expirationDate, time);
one.setExpirationDate(newDate2);
update(one, new QueryWrapper<UserServerProject>().eq("server_ip", ip).eq("project_name", name));
}
}
@Override
public List<UserServerProject> getpro(String ip) {
List<UserServerProject> list = list(new QueryWrapper<UserServerProject>().eq("server_ip", ip).ge("expiration_date", DateUtil.date()));
return list;
}
@Override
public List<UserServerProject> getproAndOpen(String ip) {
List<UserServerProject> list = list(new QueryWrapper<UserServerProject>().eq("server_ip", ip).eq("open", 1).ge("expiration_date", DateUtil.date()));
return list;
}
@Override
public UserServerProject getByIPAndName(String serverIp, String projectName) {
return getOne(new QueryWrapper<UserServerProject>().eq("server_ip", serverIp).eq("project_name", projectName).ge("expiration_date", DateUtil.date()));
}
@Override
public List<UserServerProject> getByUserName(String userName) {
return list(new QueryWrapper<UserServerProject>().eq("user_name", userName).ge("expiration_date", DateUtil.date()));
}
@Override
public String setproOpen(String ip, String projectName, String open, String userName) {
UserServerProject one = getOne(new QueryWrapper<UserServerProject>().eq("server_ip", ip).eq("project_name", projectName));
if (one!=null){
one.setOpen(Integer.parseInt(open));
update(one, new QueryWrapper<UserServerProject>().eq("server_ip", ip).eq("project_name", projectName));
return "操作成功";
}else {
return "账号下不存在此项目,请检查项目所有权是否为该账号";
}
}
}

View File

@@ -0,0 +1,292 @@
package com.example.sjkbf.service.impl;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.log.StaticLog;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.sjkbf.common.FileManage;
import com.example.sjkbf.controller.verifyController;
import com.example.sjkbf.entity.DTO.LoginRequest;
import com.example.sjkbf.entity.Log;
import com.example.sjkbf.entity.ProjectPer;
import com.example.sjkbf.entity.User;
import com.example.sjkbf.entity.UserAndServer;
import com.example.sjkbf.entity.projectconfig.Project;
import com.example.sjkbf.mapper.UserMapper;
import com.example.sjkbf.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.Objects;
import java.util.Random;
/**
* <p>
* 服务实现类
* </p>
*
* @author bozhiqiang
* @since 2025-04-15
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ProjectPerService projectPerService;
@Autowired
private UserAndServerService userAndServerService;
@Autowired
private UserServerProjectService userServerProjectService;
@Autowired
private LogService logService;
@Autowired
FileManage fileManage;
// 检查用户名是否存在
public boolean isUsernameExist(String username) {
return userMapper.selectCount(new QueryWrapper<User>().eq("username", username)) > 0;
}
// 注册用户
public void registerUser(LoginRequest request) {
User user = new User();
user.setUsername(request.getUsername());
user.setPassword(passwordEncoder.encode(request.getPassword())); // 密码加密
user.setQq(request.getQq());
user.setGold(0);
user.setName(generateRandomString());
save(user);
}
public static String generateRandomString() {
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 8; i++) {
int index = random.nextInt(characters.length());
sb.append(characters.charAt(index));
}
return sb.toString();
}
@Override
@Transactional//开启事务 保证同时成功或者失败
public String buy(String ip, String projectName, String userName) {
//获得插件项目信息
Project byName = projectPerService.getByName(projectName);
if (byName==null)return "查询不到该插件项目";
if (userAndServerService.selectCount(ip, userName)==0){
return "账号下不存在此服务器";
}
User username = getOne(new QueryWrapper<User>().eq("username", userName));
int demandGold = projectPerService.getProjectPrice(projectName);
if (demandGold>0) {
StaticLog.info("用户:"+userName+"购买项目:"+projectName+" IP"+userName);
//扣减金币
if (username.getGold() < demandGold){
StaticLog.info("用户:"+userName+"购买项目:"+projectName+" IP"+userName+"积分不足");
return "积分不足";
}
username.setGold(username.getGold() - demandGold);
updateById(username);
verifyController.ipAndMac.remove( ip);
}
// 这里还要对服务器脚本数据库进行添加
userServerProjectService.addpro(ip, projectName, 31, userName);
try {
FileWriter writer = new FileWriter("/root/java/"+"log.txt");
String now = DateUtil.now();
writer.append(now + "用户:"+userName+"购买项目:"+projectName+" IP"+userName +"购买完成");
Log log1 = new Log();
log1.setName(userName);
log1.setLog("购买项目:"+projectName+" IP"+ip +"购买完成,花费积分"+ demandGold);
if (demandGold>0){
log1.setType(3);
}else {
log1.setType(2);
}
log1.setTime(DateUtil.date());
logService.save(log1);
}catch (Exception e){
StaticLog.info("用户:"+userName+"购买项目:"+projectName+" IP"+userName+"写入日志失败");
e.printStackTrace();
}
return "购买成功";
}
@Override
public void updatePassword(LoginRequest request) {
String username = request.getUsername();
User username1 = getOne(new QueryWrapper<User>().eq("username", username));
if (username1!=null && Objects.equals(request.getQq(), username1.getQq())){
username1.setPassword(passwordEncoder.encode(request.getPassword()));
updateById(username1);
}else {
throw new RuntimeException("验证信息错误");
}
}
@Override
public String addServer(String ip, String userName, String account, String password, String port) {
// if (userAndServerService.selectCount(ip, userName)>0){
// return "该服务器已存在,请不要重复添加";
// }
UserAndServer one = userAndServerService.getOne(new QueryWrapper<UserAndServer>().eq("server_ip", ip).eq("user_name", userName));
if (one!=null){
one.setAccount(account);
one.setPassword(password);
one.setPort(port);
userAndServerService.update(one, new QueryWrapper<UserAndServer>().eq("server_ip", ip).eq("user_name", userName));
}else {
UserAndServer userAndServer = new UserAndServer();
userAndServer.setUserName(userName);
userAndServer.setServerIp(ip);
userAndServer.setAccount(account);
userAndServer.setPassword(password);
userAndServer.setPort(port);
userAndServerService.save(userAndServer);
}
return "添加成功";
}
@Override
public String deleteServer(String ip, String userName) {
if (userAndServerService.selectCount(ip, userName)>0){
userAndServerService.remove(new QueryWrapper<UserAndServer>().eq("server_ip", ip).eq("user_name", userName));
return "删除成功";
}
return "删除失败";
}
@Override
public String setKey(String userName, String clientkey, String serverkey) {
User username = getOne(new QueryWrapper<User>().eq("username", userName));
if (username!=null){
if (clientkey!=null) {
username.setClientKey(clientkey);
}
if (serverkey!=null) {
username.setServerKey(serverkey);
}
updateById(username);
return "设置成功";
}
return "设置 请重新登录后再试";
}
@Override
public String addgold(String userName, Integer gold) {
User username = getOne(new QueryWrapper<User>().eq("username", userName));
if (gold == 200){
gold= 220;
}
if (gold == 500){
gold= 570;
}
if (username!=null){
username.setGold(username.getGold()+gold);
updateById(username);
//记录日志
FileWriter writer = new FileWriter(fileManage.getFile()+"log.txt");
String now = DateUtil.now();
writer.append(now+ ""+userName+"充值"+gold+"成功\r\n");
Log log1 = new Log();
log1.setName(userName);
log1.setLog("充值"+gold+"成功");
log1.setType(1);
log1.setTime(DateUtil.date());
logService.save(log1);
return "充值成功";
}
return "充值失败";
}
@Override
@Transactional
public String transfer(String myName, String username, Integer gold) {
// 按固定顺序锁定账户,避免死锁
String firstLock = myName.compareTo(username) < 0 ? myName : username;
String secondLock = myName.compareTo(username) < 0 ? username : myName;
// 使用for update锁定账户
User firstUser = getOne(new QueryWrapper<User>()
.eq("username", firstLock)
.last("for update"));
User secondUser = getOne(new QueryWrapper<User>()
.eq("username", secondLock)
.last("for update"));
// 由于锁定顺序固定,我们需要根据实际转账方向确定哪个是转出账户,哪个是转入账户
User myUser = firstLock.equals(myName) ? firstUser : secondUser;
User targetUser = firstLock.equals(myName) ? secondUser : firstUser;
if (targetUser == null) {
return "被转让用户不存在,请检查用户名";
}
if (myUser.getGold() < gold) {
return "余额不足";
}
// 更新余额
myUser.setGold(myUser.getGold() - gold);
updateById(myUser);
targetUser.setGold(targetUser.getGold() + gold);
updateById(targetUser);
// 记录日志
Log log1 = new Log();
log1.setName(myName);
log1.setLog(myName + "" + username + "转让" + gold + "积分");
log1.setType(4);
log1.setTime(DateUtil.date());
logService.save(log1);
return "转让完毕";
}
}

View File

@@ -0,0 +1,340 @@
package com.example.sjkbf.util;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
* JavaFX视频播放器 - 用于测试服务端视频流
*/
public class JavaFXVideoPlayer extends Application {
private MediaPlayer mediaPlayer;
private MediaView mediaView;
private Label statusLabel;
private ProgressBar progressBar;
private TextField projectField;
private TextField videoNameField;
private TextField serverUrlField;
private Button playButton;
private Button pauseButton;
private Button stopButton;
private Slider volumeSlider;
private Slider seekSlider;
private DoubleProperty playbackRate;
private static final String DEFAULT_SERVER = "http://localhost:8651";
@Override
public void start(Stage primaryStage) {
playbackRate = new SimpleDoubleProperty(1.0);
// 创建UI组件
createUIComponents();
// 布局
VBox root = createLayout();
// 场景
Scene scene = new Scene(root, 1000, 700);
scene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
// 舞台设置
primaryStage.setTitle("视频流测试播放器");
primaryStage.setScene(scene);
primaryStage.setOnCloseRequest(event -> cleanup());
primaryStage.show();
}
private void createUIComponents() {
// 输入字段
serverUrlField = new TextField(DEFAULT_SERVER);
serverUrlField.setPromptText("服务器地址");
projectField = new TextField("战令");
projectField.setPromptText("项目名称");
videoNameField = new TextField("2");
videoNameField.setPromptText("视频名称");
// 控制按钮
playButton = new Button("播放");
playButton.setOnAction(e -> playVideo());
pauseButton = new Button("暂停");
pauseButton.setOnAction(e -> pauseVideo());
pauseButton.setDisable(true);
stopButton = new Button("停止");
stopButton.setOnAction(e -> stopVideo());
stopButton.setDisable(true);
// 媒体视图
mediaView = new MediaView();
mediaView.setFitWidth(800);
mediaView.setFitHeight(450);
mediaView.setPreserveRatio(true);
// 进度条和滑块
progressBar = new ProgressBar(0);
progressBar.setPrefWidth(800);
seekSlider = new Slider(0, 100, 0);
seekSlider.setPrefWidth(800);
seekSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
if (seekSlider.isValueChanging() && mediaPlayer != null) {
Duration duration = mediaPlayer.getTotalDuration();
if (duration != null) {
mediaPlayer.seek(duration.multiply(newVal.doubleValue() / 100.0));
}
}
});
// 音量控制
volumeSlider = new Slider(0, 100, 50);
volumeSlider.setPrefWidth(150);
volumeSlider.valueProperty().addListener((obs, oldVal, newVal) -> {
if (mediaPlayer != null) {
mediaPlayer.setVolume(newVal.doubleValue() / 100.0);
}
});
// 状态标签
statusLabel = new Label("准备就绪");
statusLabel.setStyle("-fx-text-fill: #2E8B57; -fx-font-weight: bold;");
}
private VBox createLayout() {
VBox root = new VBox(15);
root.setPadding(new Insets(15));
root.setStyle("-fx-background-color: #2F4F4F;");
// 标题
Label titleLabel = new Label("服务端视频流测试播放器");
titleLabel.setStyle("-fx-text-fill: white; -fx-font-size: 20px; -fx-font-weight: bold;");
// 输入区域
GridPane inputGrid = new GridPane();
inputGrid.setHgap(10);
inputGrid.setVgap(10);
inputGrid.setPadding(new Insets(10));
inputGrid.setStyle("-fx-background-color: #556B2F; -fx-background-radius: 5;");
inputGrid.add(new Label("服务器:"), 0, 0);
inputGrid.add(serverUrlField, 1, 0);
inputGrid.add(new Label("项目:"), 0, 1);
inputGrid.add(projectField, 1, 1);
inputGrid.add(new Label("视频:"), 0, 2);
inputGrid.add(videoNameField, 1, 2);
serverUrlField.setPrefWidth(300);
projectField.setPrefWidth(200);
videoNameField.setPrefWidth(200);
// 控制按钮区域
HBox controlBox = new HBox(10);
controlBox.setAlignment(Pos.CENTER);
controlBox.getChildren().addAll(playButton, pauseButton, stopButton);
// 音量控制
HBox volumeBox = new HBox(10);
volumeBox.setAlignment(Pos.CENTER_LEFT);
volumeBox.getChildren().addAll(new Label("音量:"), volumeSlider);
// 播放速率控制
HBox rateBox = new HBox(10);
rateBox.setAlignment(Pos.CENTER_LEFT);
ComboBox<String> rateCombo = new ComboBox<>();
rateCombo.getItems().addAll("0.5x", "1.0x", "1.5x", "2.0x");
rateCombo.setValue("1.0x");
rateCombo.setOnAction(e -> {
String selected = rateCombo.getValue();
double rate = Double.parseDouble(selected.replace("x", ""));
playbackRate.set(rate);
if (mediaPlayer != null) {
mediaPlayer.setRate(rate);
}
});
rateBox.getChildren().addAll(new Label("播放速度:"), rateCombo);
// 状态区域
HBox statusBox = new HBox(10);
statusBox.setAlignment(Pos.CENTER);
statusBox.getChildren().addAll(statusLabel, progressBar);
// 组装所有组件
root.getChildren().addAll(
titleLabel,
inputGrid,
controlBox,
new Separator(),
mediaView,
new Label("播放进度:"),
seekSlider,
new Separator(),
volumeBox,
rateBox,
statusBox
);
return root;
}
private void playVideo() {
try {
String serverUrl = serverUrlField.getText().trim();
String project = projectField.getText().trim();
String videoName = videoNameField.getText().trim();
if (project.isEmpty() || videoName.isEmpty()) {
showError("请填写项目名称和视频名称");
return;
}
// 编码URL参数
String encodedProject = URLEncoder.encode(project, StandardCharsets.UTF_8.toString());
String encodedVideoName = URLEncoder.encode(videoName, StandardCharsets.UTF_8.toString());
String videoUrl = String.format("%s/api/videos/%s/%s",
serverUrl, encodedProject, encodedVideoName);
updateStatus("正在连接: " + videoUrl);
// 清理之前的播放器
if (mediaPlayer != null) {
mediaPlayer.dispose();
}
// 创建新的媒体播放器
Media media = new Media(videoUrl);
mediaPlayer = new MediaPlayer(media);
mediaView.setMediaPlayer(mediaPlayer);
// 设置播放速率
mediaPlayer.setRate(playbackRate.get());
mediaPlayer.setVolume(volumeSlider.getValue() / 100.0);
// 设置事件监听器
setupMediaListeners();
// 开始播放
mediaPlayer.play();
updateStatus("正在播放: " + project + "/" + videoName);
// 更新按钮状态
playButton.setDisable(true);
pauseButton.setDisable(false);
stopButton.setDisable(false);
} catch (UnsupportedEncodingException e) {
showError("URL编码错误: " + e.getMessage());
} catch (Exception e) {
showError("播放错误: " + e.getMessage());
e.printStackTrace();
}
}
private void setupMediaListeners() {
mediaPlayer.setOnReady(() -> {
updateStatus("媒体已加载完成");
progressBar.setProgress(0);
});
mediaPlayer.setOnPlaying(() -> {
updateStatus("播放中...");
});
mediaPlayer.setOnPaused(() -> {
updateStatus("已暂停");
});
mediaPlayer.setOnStopped(() -> {
updateStatus("已停止");
resetControls();
});
mediaPlayer.setOnEndOfMedia(() -> {
updateStatus("播放完成");
resetControls();
progressBar.setProgress(1.0);
});
mediaPlayer.setOnError(() -> {
String errorMessage = mediaPlayer.getError() != null ?
mediaPlayer.getError().getMessage() : "未知错误";
showError("媒体错误: " + errorMessage);
resetControls();
});
// 更新进度条
mediaPlayer.currentTimeProperty().addListener((obs, oldTime, newTime) -> {
if (mediaPlayer.getTotalDuration().greaterThan(Duration.ZERO)) {
double progress = newTime.toMillis() / mediaPlayer.getTotalDuration().toMillis();
progressBar.setProgress(progress);
seekSlider.setValue(progress * 100);
}
});
}
private void pauseVideo() {
if (mediaPlayer != null) {
mediaPlayer.pause();
pauseButton.setDisable(true);
playButton.setDisable(false);
}
}
private void stopVideo() {
if (mediaPlayer != null) {
mediaPlayer.stop();
resetControls();
}
}
private void resetControls() {
playButton.setDisable(false);
pauseButton.setDisable(true);
stopButton.setDisable(true);
progressBar.setProgress(0);
seekSlider.setValue(0);
}
private void updateStatus(String message) {
Platform.runLater(() -> {
statusLabel.setText(message);
statusLabel.setStyle("-fx-text-fill: #2E8B57; -fx-font-weight: bold;");
});
}
private void showError(String message) {
Platform.runLater(() -> {
statusLabel.setText("错误: " + message);
statusLabel.setStyle("-fx-text-fill: #FF4500; -fx-font-weight: bold;");
});
}
private void cleanup() {
if (mediaPlayer != null) {
mediaPlayer.dispose();
}
}
public static void main(String[] args) {
launch(args);
}
}

View File

@@ -0,0 +1,171 @@
package com.example.sjkbf.util;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;
/**
* JWT 工具类
* - 负责 Token 的生成、解析、验证
* - 采用 HMAC-SHA 算法进行签名,保证安全性
* - 适配 JJWT 0.11.x 版本
*/
@Component
public class JwtTokenUtil {
// 从配置文件中注入 JWT 密钥和过期时间
@Value("${jwt.secret}")
private String secret; // 密钥(至少 32 位,推荐 64 位随机字符串)
@Value("${jwt.expiration}")
private Long expiration; // Token 有效期(秒)
/**
* 生成安全的 HMAC-SHA 密钥
* - 避免直接使用原始字符串,提升安全性
*/
private SecretKey generateSecretKey() {
return Keys.hmacShaKeyFor(secret.getBytes());
}
/**
* 生成 Token
* @param userDetails 用户信息(包含用户名、权限等)
* @return Token 字符串
*/
public String generateToken(UserDetails userDetails) {
// 1. 定义 Token 的 Claims载荷
Map<String, Object> claims = new HashMap<>();
claims.put("username", userDetails.getUsername());
// 将权限列表转换为字符串(例如 "ROLE_ADMIN,ROLE_USER"
claims.put("authorities", userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()));
// 2. 生成 Token
return Jwts.builder()
.setClaims(claims) // 自定义载荷
.setSubject(userDetails.getUsername()) // 主题(通常放用户名)
.setIssuedAt(new Date()) // 签发时间
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)) // 过期时间
.signWith(generateSecretKey()) // 签名算法和密钥
.compact(); // 生成字符串
}
/**
* 从 Token 中解析用户名
* @param token JWT Token
* @return 用户名
*/
public String getUsernameFromToken(String token) {
return parseToken(token).getSubject();
}
/**
* 从 Token 中解析权限列表
* @param token JWT Token
* @return 权限列表(例如 ["ROLE_ADMIN", "ROLE_USER"]
*/
public List<String> getAuthoritiesFromToken(String token) {
Claims claims = parseToken(token);
return claims.get("authorities", List.class);
}
/**
* 验证 Token 是否有效(基础验证)
* - 检查签名是否正确
* - 检查是否过期
* @param token JWT Token
* @return 是否有效
*/
public boolean validateToken(String token) {
Claims claims = parseToken(token);
// 检查是否过期parseToken 内部已自动验证过期时间)
return !claims.getExpiration().before(new Date());
}
/**
* 验证 Token 是否属于指定用户(业务层扩展验证)
* @param token JWT Token
* @param userDetails 用户信息
* @return 是否匹配
*/
public boolean validateTokenBelongsToUser(String token, UserDetails userDetails) {
String username = getUsernameFromToken(token);
return username.equals(userDetails.getUsername());
}
/**
* 解析 Token内部方法
* @param token JWT Token
* @return 解析后的 Claims 对象
* @throws JwtException 解析失败时抛出异常(如签名错误、格式错误)
*/
public Claims parseToken(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(generateSecretKey())
.build()
.parseClaimsJws(token)
.getBody();
} catch (JwtException e) {
throw new JwtException("Token 已过期");
}
}
// ---------- 扩展方法:自定义 Claims ----------
/**
* 添加自定义 Claim在生成 Token 前调用)
* 示例添加用户ID
* Map<String, Object> claims = new HashMap<>();
* claims.put("userId", 123);
* String token = jwtTokenUtil.generateToken(userDetails, claims);
*/
public String generateToken(UserDetails userDetails, Map<String, Object> customClaims) {
Map<String, Object> claims = new HashMap<>();
claims.putAll(customClaims); // 合并自定义 Claims
claims.put("authorities", userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()));
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration * 1000))
.signWith(generateSecretKey())
.compact();
}
/**
* 获取自定义 Claim
* 示例Long userId = jwtTokenUtil.getClaimFromToken(token, "userId", Long.class);
*/
public <T> T getClaimFromToken(String token, String claimName, Class<T> clazz) {
Claims claims = parseToken(token);
return claims.get(claimName, clazz);
}
/**
* 从请求中获取 Token
* @param request
* @return
*/
public String getTokenFromRequest(HttpServletRequest request) {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
return header.substring(7);
}
return null;
}
}

View File

@@ -0,0 +1,44 @@
package com.example.sjkbf.util;
import java.security.MessageDigest;
public class MD5 {
// 全局数组
private final static String[] strDigits = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "j", "?", "~"};
// 返回形式为数字跟字符串
private static String byteToArrayString(byte bByte) {
int iRet = bByte;
if (iRet < 0) {
iRet += 256;
}
int iD1 = iRet / 16;
int iD2 = iRet % 16;
return strDigits[iD1] + strDigits[iD2];
}
// 转换字节数组为16进制字串
private static String byteToString(byte[] bByte) {
StringBuffer sBuffer = new StringBuffer();
for (int i = 0; i < bByte.length; i++) {
sBuffer.append(byteToArrayString(bByte[i]));
}
return sBuffer.toString();
}
public static String getMD5Code(String strObj) {
String resultString = null;
try {
// resultString = new String(strObj);
MessageDigest md = MessageDigest.getInstance("MD5");
// md.digest() 该函数返回值为存放哈希值结果的byte数组
resultString = byteToString(md.digest(strObj.getBytes("UTF-8")));
} catch (Exception e) {
e.printStackTrace();
}
return resultString;
}
}

View File

@@ -0,0 +1,223 @@
package com.example.sjkbf.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class RSATooL {
private static String prkey = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANp/KnuAZq609lnc\n" +
"jciVgt/xDLDEaKC+DSuSZc9o/fgLqweL/8Yu5iPAzoBQlO1t+jSkI2YuoFsKKK7O\n" +
"QFcSoz4Z5Lb7vOG7XJ4Re/6L2LJIU9tjJ3LznW5WKnuiqxs0ziIZilLkRE0P1di6\n" +
"FIZQUjmn2KQ2y/P7PuviJPat3y+vAgMBAAECgYEAmn64h0MvV/FVEA1Ho8E0HSzQ\n" +
"kF0Qrjg0D88gdhwDGFUHxfpUDMo0qKs4WLqh05CkDnzRGvt1H2p7gb8M94SSL5SX\n" +
"mCR2ZLiCQJy5tZpQNRUt9P67upLcDcKJ6YPujcuEdlo0pzKGGMZk8Uvh05S9lnwl\n" +
"yWJeEk4G7q5Aalz8vIECQQDwBVJH60Gd2St/GS4dCtXwHTO9HJZRaWEkaXPgVbXI\n" +
"vqv+jtD4HpzDCpgv/kUK0fnb4V/9/LM1SHOedVMfmh0fAkEA6QsChdHiU1lHfL1b\n" +
"Z3Uvxvi/Zk8i0ryzBaYudrzNmb7iJcssJPPty3KTjihgvw2W36GV+2GlQBEjOf2B\n" +
"2WgLcQJBAO66XDxsIbd+aWThBpycSm2one1aoagXyCcPO9HFbilcfHWUVwRybjkQ\n" +
"MI6LuOAqOPoaD//vd89nYJga2bJ09sECQFmXRPoDTVozqXr4JSqp75szyAliBQY1\n" +
"SzGxyI0XWodvzesvp6HxMQsU2ks9lKv+YnFI4qsIyAnQTNWfcwsMp9ECQDba0LJV\n" +
"xI0SIznsVtBb7T5Ir9ppLKx1QTNcytkjHxmQqWGy+57ojjQ6GV3z4fSwNGjIhsOT\n" +
"DFgz0gEcRr13bRk=";
private static String pubkey =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDafyp7gGautPZZ3I3IlYLf8Qyw\n" +
"xGigvg0rkmXPaP34C6sHi//GLuYjwM6AUJTtbfo0pCNmLqBbCiiuzkBXEqM+GeS2\n" +
"+7zhu1yeEXv+i9iySFPbYydy851uVip7oqsbNM4iGYpS5ERND9XYuhSGUFI5p9ik\n" +
"Nsvz+z7r4iT2rd8vrwIDAQAB";
static RSA rsa2 = new RSA(prkey, pubkey);
/**
* 解密
* @param str
* @return
*/
public static String decrypt(String str){
str= str.replaceAll(" ","+");
byte[] decrypt2 = rsa2.decrypt(str, KeyType.PrivateKey);
String s = new String(decrypt2);
String[] split = s.split("");
s = split[0];
return s;
}
/**
* 加密
* @param str
* @return
*/
public static String encryption(String str){
return Base64.encode(rsa2.encrypt(str, KeyType.PrivateKey));
}
/**
* 使用RSA公钥解密
* @param encryptedData 加密后的数据Base64编码
* @return 解密后的原始字符串
*/
public static String decryptByPublicKey( String encryptedData) {
// 解密步骤:
// 1. 将Base64编码的加密数据解码为字节数组
// 2. 使用公钥解密指定KeyType.PublicKey
// 3. 将解密后的字节数组转换为字符串
byte[] decryptedBytes = rsa2.decrypt(Base64.decode(encryptedData), KeyType.PublicKey);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
public static void main(String[] args) {
System.out.println(decompress("H4sIAAAAAAAAAKtWyk6tVLJSUggKdgzJz/fRS81LLqosKMnMz9MAyhTrleQHlxRl5qVraCrVAgAXNYHCLQAAAA=="));
}
//异或加密
public static byte[] Makecode(byte[] pstr,int[] Key) {
byte[] Str = pstr;
for (int i = 0; i < Str.length; i++) {
byte sbuf = Str[i];
Str[i] = MakecodeChar(sbuf, Key[i % 20], Key[(i + 18) % 20]);
}
return Str;
}
//字符串异或
public static String encryptDecrypt(String input, String key) {
StringBuilder output = new StringBuilder(input);
int keyLength = key.length();
for (int i = 0; i < input.length(); i++) {
// 对每个字符进行异或运算
output.setCharAt(i, (char) (input.charAt(i) ^ key.charAt(i % keyLength)));
}
return output.toString();
}
//单个字符加密
public static byte MakecodeChar(byte c, int key, int key2) {
return (byte) ((((c + key) ^ key2) ^ key) + 1);
}
/**
* 单个字符解密对应C++的CutcodeChar
* @param c 待解密的字符Java中用byte表示对应C++的char
* @param key 第一个密钥
* @param key2 第二个密钥
* @return 解密后的字符byte
*/
public static byte cutcodeChar(byte c, int key, int key2) {
// 对应C++的:(((c - 1) ^ key) ^ key2) - key
// 注意Java中byte是8位有符号数运算时会自动提升为int最后强转为byte
int step1 = (c - 1) ^ key;
int step2 = step1 ^ key2;
int result = step2 - key;
return (byte) result;
}
/**
* 字节数组解密对应C++的Cutecode
* @param pstr 待解密的字节数组对应C++的char*
* @param pkey 密钥数组
* @param len 待解密的长度(-1表示使用整个数组长度
* @param keyLength 密钥长度默认5与C++默认参数一致)
* @return 解密后的字节数组(原数组会被修改,同时返回新数组方便链式调用)
*/
public static byte[] cutecode(byte[] pstr, int[] pkey, int len, int keyLength) {
// 处理默认长度如果len为-1则使用数组的实际长度
if (len == -1) {
len = pstr.length;
}
// 遍历每个字节进行解密
for (int i = 0; i < len; i++) {
// 计算密钥索引与C++逻辑一致
int keyIndex = i % keyLength;
int key2Index = (i + 18) % keyLength;
// 调用单个字符解密方法,修改原数组
pstr[i] = cutcodeChar(pstr[i], pkey[keyIndex], pkey[key2Index]);
}
return pstr;
}
// 重载方法提供默认参数对应C++的默认参数int keyLength = 5
public static byte[] cutecode(byte[] pstr, int[] pkey, int len) {
return cutecode(pstr, pkey, len, 5);
}
// 重载方法最简化调用len=-1keyLength=5
public static byte[] cutecode(byte[] pstr, int[] pkey) {
return cutecode(pstr, pkey, -1, 5);
}
/**
* 压缩字符串
* @param input 原始字符串
* @return Base64编码后的压缩字符串便于存储/传输)
*/
public static String compress(String input) {
if (input == null || input.isEmpty()) {
return input;
}
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
GZIPOutputStream gzipOS = new GZIPOutputStream(bos)) {
gzipOS.write(input.getBytes(StandardCharsets.UTF_8));
gzipOS.finish();
// 将压缩后的字节数组转为Base64字符串避免二进制乱码
byte[] compressedBytes = bos.toByteArray();
return java.util.Base64.getEncoder().encodeToString(compressedBytes);
} catch (IOException e) {
throw new RuntimeException("压缩失败", e);
}
}
/**
* 解压字符串
* @param compressedStr Base64编码后的压缩字符串
* @return 解压后的原始字符串
*/
public static String decompress(String compressedStr) {
if (compressedStr == null || compressedStr.isEmpty()) {
return compressedStr;
}
byte[] compressedBytes = java.util.Base64.getDecoder().decode(compressedStr);
System.out.println(Arrays.toString(compressedBytes));
try (ByteArrayInputStream bis = new ByteArrayInputStream(compressedBytes);
GZIPInputStream gzipIS = new GZIPInputStream(bis);
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = gzipIS.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
return new String(bos.toByteArray(), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("解压失败", e);
}
}
}

View File

@@ -0,0 +1,250 @@
package com.example.sjkbf.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.json.JSONObject;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import java.io.*;
import java.nio.file.*;
import java.util.Arrays;
import java.util.zip.*;
public class SimpleNutZipCompatible {
// 字节级别的加密解密
public static byte[] encryptDecryptBytes(byte[] data, String key) {
byte[] result = new byte[data.length];
byte[] keyBytes = key.getBytes();
for (int i = 0; i < data.length; i++) {
result[i] = (byte) (data[i] ^ keyBytes[i % keyBytes.length]);
}
return result;
}
public static void main(String[] args) {
String operation = "encrypt"; // 或 "decrypt"
String sourcePath = "C:\\Users\\12134\\Desktop\\fsdownload\\DPS_Script";
String targetPath = "C:\\Users\\12134\\Desktop\\fsdownload\\DPS_Script\\sut.tar.gz";
String key = "Rindro-Aurora";
if ("encrypt".equals(operation)) {
// 加密并压缩
encryptAndZip(sourcePath, targetPath, key);
} else {
// 解压并解密
decryptFromZip(sourcePath, targetPath, key);
}
}
/**
* 检查文件是否在_Core子目录下
*/
private static boolean isInRootOrCore(Path filePath, Path sourcePath) {
Path relativePath = sourcePath.relativize(filePath);
int nameCount = relativePath.getNameCount();
// _Core子目录下的文件相对路径的第一个目录是_Core
if (nameCount >= 2 && "_Core".equals(relativePath.getName(0).toString())) {
return true;
}
return false;
}
public static void encryptAndZip(String folderPath, String zipPath, String key) {
// 随机生成密钥
byte[] keyBytes = {92, -2, -65, 10, 118, 103, -68, 72, -23, 124, -103, -39, 0, -128, 31, -107};
System.out.println("密钥: " + Arrays.toString(keyBytes));
// 构建
AES aes = SecureUtil.aes(keyBytes);
Path tempDir = null;
try {
// 创建临时目录
tempDir = Files.createTempDirectory("nut_encrypt");
Path sourcePath = Paths.get(folderPath);
// 加密所有.nut文件到临时目录
Path finalTempDir = tempDir;
Files.walk(sourcePath)
.filter(Files::isRegularFile)
.filter(path -> (path.toString().toLowerCase().endsWith(".nut")))
.filter(path -> isInRootOrCore(path, sourcePath))
.forEach(nutFile -> {
try {
byte[] content = Files.readAllBytes(nutFile);
byte[] encrypted = aes.encrypt(content);
Path relative = sourcePath.relativize(nutFile);
Path tempFile = finalTempDir.resolve(relative);
String newName = tempFile.getFileName().toString().replace(".nut", ".nut");
Path sutFile = tempFile.getParent().resolve(newName);
Files.createDirectories(sutFile.getParent());
Files.write(sutFile, encrypted);
System.out.println("加密: " + relative);
} catch (Exception e) {
System.err.println("错误: " + nutFile + " - " + e.getMessage());
}
});
FileReader fileReader = new FileReader(folderPath + "/FileConfig.json");
String result5 = fileReader.readString();
//转json
JSONObject jsonObject = new JSONObject(result5);
jsonObject.remove("ProjectScript");
String string = tempDir.toAbsolutePath()+"/FileConfig.json";
FileUtil.writeString(jsonObject.toString(),string, "utf-8");
// 压缩临时目录
zipFolderToTarGz(tempDir.toString(), zipPath);
System.out.println("压缩完成: " + zipPath);
} catch (Exception e) {
System.err.println("加密压缩失败: " + e.getMessage());
} finally {
if (tempDir != null) {
deleteDirectory(tempDir.toFile());
}
}
}
public static void decryptFromZip(String zipPath, String outputFolder, String key) {
try {
Path outputPath = Paths.get(outputFolder);
Files.createDirectories(outputPath);
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipPath))) {
ZipEntry entry;
byte[] buffer = new byte[1024];
while ((entry = zis.getNextEntry()) != null) {
if (!entry.isDirectory() && entry.getName().toLowerCase().endsWith(".sut")) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
while ((len = zis.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
byte[] encrypted = baos.toByteArray();
byte[] decrypted = encryptDecryptBytes(encrypted, key);
Path outputFile = outputPath.resolve(entry.getName());
String newName = outputFile.getFileName().toString().replace(".sut", ".nut");
Path nutFile = outputFile.getParent().resolve(newName);
Files.createDirectories(nutFile.getParent());
Files.write(nutFile, decrypted);
System.out.println("解密: " + entry.getName());
}
zis.closeEntry();
}
}
System.out.println("解密完成: " + outputFolder);
} catch (Exception e) {
System.err.println("解压解密失败: " + e.getMessage());
}
}
private static void zipFolder(String srcFolder, String zipPath) {
try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
File folder = new File(srcFolder);
zipDirectory(folder, zos, "");
} catch (IOException e) {
System.err.println("压缩错误: " + e.getMessage());
}
}
private static void zipDirectory(File folder, ZipOutputStream zos, String parentPath) throws IOException {
for (File file : folder.listFiles()) {
if (file.isDirectory()) {
zipDirectory(file, zos, parentPath + file.getName() + "/");
} else {
try (FileInputStream fis = new FileInputStream(file)) {
zos.putNextEntry(new ZipEntry(parentPath + file.getName()));
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
zos.write(buffer, 0, length);
}
zos.closeEntry();
}
}
}
}
/**
* 将文件夹压缩为 tar.gz 格式
*/
private static void zipFolderToTarGz(String sourceFolder, String tarGzPath) throws IOException {
Path sourcePath = Paths.get(sourceFolder);
try (FileOutputStream fos = new FileOutputStream(tarGzPath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
GZIPOutputStream gos = new GZIPOutputStream(bos);
TarArchiveOutputStream tos = new TarArchiveOutputStream(gos)) {
// 设置tar格式
tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
Files.walk(sourcePath)
.filter(Files::isRegularFile)
.forEach(file -> {
try {
// 获取相对路径
Path relativePath = sourcePath.relativize(file);
// 创建tar条目
TarArchiveEntry entry = new TarArchiveEntry(file.toFile(), relativePath.toString().replace("\\", "/"));
tos.putArchiveEntry(entry);
// 写入文件内容
Files.copy(file, tos);
tos.closeArchiveEntry();
// System.out.println("添加到tar.gz: " + relativePath);
} catch (IOException e) {
System.err.println("添加文件到tar.gz失败: " + file + " - " + e.getMessage());
}
});
tos.finish();
}
}
private static void deleteDirectory(File dir) {
if (dir.isDirectory()) {
for (File file : dir.listFiles()) {
deleteDirectory(file);
}
}
dir.delete();
}
}

View File

@@ -0,0 +1,118 @@
package com.example.sjkbf.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import javax.servlet.http.HttpServletRequest;
public class tool {
public static String encryptDecrypt(String input, String key) {
char[] output = new char[input.length()];
for (int i = 0; i < input.length(); i++) {
output[i] = (char) (input.charAt(i) ^ key.charAt(i % key.length())); // 使用异或运算进行加密
}
return new String(output);
}
private static final String prkey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAMiYuNW4K1rST7ZW" +
"YpWX6nEziXi5JveLPhDCLj0VZ/5/4dzBWrmoL/IcFZuHOBJtYHm965713kKC9gtw" +
"2EyVgkqmXLT3105jEUqzNizfThc6C2ZL6vMmzUZlooxNyaOC5mWthPZtwlqQihYW" +
"T2nW/wKp8fpTouXihQOCPjqdRoVFAgMBAAECgYEAg+1dcsHjUaIL5uG9iKEXAUhh" +
"21H6PMgJE8CB5I6VjJ3Sj/tijcP9dH/f/h/aUtQ4pRixRCRz/s5ev3uB5ixWOVOz" +
"Uhga/NwjURlkg1Katg/14tvd8iZsAzI7KyXGdUefC8+Rulc8SBx+BqYIZ1FTLJkg" +
"obisps6esaaNZekvS0ECQQDxPnfWuNfwfpYFK038AhEFqBiOBMsMrB/QX+O0sQ/Z" +
"31gWkNuu3Z+cz6PG0FEK0O8/jsXQ1/gVAreADptJAMzpAkEA1N3GFV1LuYYqkp3a" +
"y4DnmdI/LgrBUAjWSvTSDKfB8Ik2Y8I2zDS20EsEQMvQYtLxMOMHIEqeAVzmnZcS" +
"dH4L/QJAQM/elFJuuU7Y8SSUO/s2JYXmqukAwDPSDEJmw5m6P3dwjAd47b7e7dsf" +
"Df/Tdgtx62ppHNWY8dQcBoxmDbPoWQJBANBQBBROS9fQA4Od9Usn5/5xcSDWp51y" +
"OHv8ID8AQNvq+44ets+aWrl2YEAk9NZxRlWoJwYj34LH7muUNxxHaeUCQQCjtLPU" +
"din4XjlMMRSTW/EOgX4JgZ+tQaAtB32wQocPDDeHqkDusUdlEpnDPbmkE9Sbxf1p" +
"0mSxXgnIuT99niBd";
private static final String prkey2 = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAIdcnQN/YkABlIDJ" +
"b2wqZgYEHRJReHvIWbeyNV7zJsMZdZRmQYKi2WMmNMH3DKyW7CCzdYrvHbQ5QyqP" +
"YaQ1X9hVv4bPzXPKSCBVPh5Cr13WwKgh3lhLmbkA/hJ9giRIo9jT47fHE3RaJkic" +
"RyCqWDSiOsnF7gNYJQf8MAarl/oTAgMBAAECgYAvZKvM57LcujDmjqCmfInQHWyY" +
"V1IZ9OIEwS6Smgu+T5GtbcgOFzqJzny2VOtpGkZ+hJbpGCOMUGhF5IHJXq65qvei" +
"ejBeJEH9xnTuJcXUKtHJjIGJQsKzuNKuTddFlY9an/BzoZq4/2Txyh2z6ZDZU1z0" +
"9pVY8tJe2FVyMY2oIQJBAKhLDMV+kfWLzDfiXijJ28DHdKCozaaAtLZRTRL/XlQU" +
"O8phcZ0wEKkzrNvn0Fn+5VIQFu1ghWvCo4iaS181FqkCQQDN5/+nbbzZ2AqQsBDB" +
"eCbLiXPJM7Ey69O4leMyzKL1dyI7nMl5/SeOQE/xBViqzF6M/VUGFzE1YOxl+HZA" +
"AQxbAkA3GNsFjXqbuTkS0rmhAPVBGAvGzX0GlfyT8+oX3iMzw6wPhfd8TtAllRVy" +
"qWI9FIZfZ4UaEg+cSAziHCGw+eCBAkAlLJWDbNSDn/WIWcEsrLyUUqSM1sBPKTR4" +
"RtdV/IwPNQsBKDVXyNSzYfkM0qJHc84+Nh57kwRXVsBXSJxQwd+xAkB9ZzCD0sp6" +
"8ISzFmbwL+uVtUbe/W0pLC9PDN9B7Vcw6Jf8V0B3lxB493rxTzG3o5oapDDxFIv/" +
"I6SViudhGXfP";
private static final String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHXJ0Df2JAAZSAyW9sKmYGBB0S" +
"UXh7yFm3sjVe8ybDGXWUZkGCotljJjTB9wysluwgs3WK7x20OUMqj2GkNV/YVb+G" +
"z81zykggVT4eQq9d1sCoId5YS5m5AP4SfYIkSKPY0+O3xxN0WiZInEcgqlg0ojrJ" +
"xe4DWCUH/DAGq5f6EwIDAQAB";
static RSA rsa2 = new RSA(prkey, null);
static RSA rsa22 = new RSA(prkey2, publicKey);
public static String getIpAddress(HttpServletRequest request) {
// 获取请求的IP地址
String ipAddress = request.getRemoteAddr();
// 如果应用部署在反向代理或负载均衡器后面可以通过X-Forwarded-For头部获取真实IP地址
String forwardedFor = request.getHeader("X-Forwarded-For");
if (forwardedFor != null && !forwardedFor.isEmpty()) {
ipAddress = forwardedFor.split(",")[0];
}
return ipAddress;
}
/**
* 解密
* @param str
* @return
*/
public static String decrypt(String str){
str= str.replaceAll(" ","+");
byte[] decrypt2 = rsa2.decrypt(str, KeyType.PublicKey);
String s = new String(decrypt2);
String[] split = s.split("");
s = split[0];
return s;
}
/**
* 加密
* @param str
* @return
*/
public static String encryption(String str){
return Base64.encode(rsa2.encrypt(str, KeyType.PrivateKey));
}
/**
* 加密2
* @param str
* @return
*/
public static String encryption2(String str){
return Base64.encode(rsa22.encrypt(str, KeyType.PrivateKey));
}
/**
* 解密
*/
public static String decrypt2(String str){
//先进行base64解密
str= Base64.decodeStr(str);
byte[] decrypt2 = rsa22.decrypt(str, KeyType.PublicKey);
String s = new String(decrypt2);
return s;
}
}

View File

@@ -0,0 +1,78 @@
server:
port: 8651
# ssl:
# key-store: classpath:yosin.jks
# key-store-type: JKS
# key-password: 2luolita
#spring:
# datasource:
# dynamic:
# primary: master #??????????????,?????master
# strict: false #???????,??false. true?????????????,false???????
# datasource:
# master:
# url: jdbc:mysql://127.0.0.1:3306/taiwan_cain_2nd?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
# username: game
# password: uu5!^%jg
# driver-class-name: com.mysql.jdbc.Driver # 3.2.0????SPI??????
jwt:
secret: "rjyusrghdfghj2345ryu123asdfvbyukuirtwjhfsd" # 至少 32 位
expiration: 7200 # 2 小时(单位:秒)
#
#
#
#spring:
# # 配置数据源信息
# datasource:
# dynamic:
# # 设置默认的数据源或者数据源组,默认值即为master
# primary: master
# # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
# strict: false
# datasource:
# master:
# url: jdbc:mysql://192.168.200.25:3306/rindro?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root2
# password: 527700
# driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0????SPI??????
#pro:
# configfile: "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\Script\\FileConfig.json"
# userfile: "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\"
# filemap: "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\file.json"
# scriptfile: "C:\\Users\\12134\\Desktop\\工作目录\\rindro\\ClentScript\\"
# dps: "C:\\Users\\12134\\Desktop\\工作目录\\home\\DP_S\\"
#
spring:
# 配置数据源信息
datasource:
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
master:
# url: jdbc:mysql://110.40.74.134:3306/rindro?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 527700
url: jdbc:mysql://110.42.251.214:3306/rindro?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: Yosin0102!
driver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0????SPI??????
pro:
configfile: "/root/rindro/Script/FileConfig.json"
userfile: "/root/rindro/"
filemap: "/root/rindro/file.json"
scriptfile: "/root/rindro/ClentScript/"
dps: "/home/DP_S/"
#mybatis-plus:
# configuration:
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 直接在控制台打印SQL

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.sjkbf.mapper.LogMapper">
</mapper>

Some files were not shown because too many files have changed in this diff Show More