init full backend repo with src + deploy config
This commit is contained in:
33
Jenkinsfile
vendored
Normal file
33
Jenkinsfile
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
pipeline {
|
||||
agent any
|
||||
environment {
|
||||
SSH_CREDENTIALS_ID = 'alex-ssh-key'
|
||||
REMOTE_HOST = '117.72.202.202'
|
||||
REMOTE_USER = 'alex'
|
||||
REMOTE_DIR = '/home/alex/alex-api'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
sh 'mvn clean package -DskipTests'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
sshagent([env.SSH_CREDENTIALS_ID]) {
|
||||
sh """
|
||||
scp target/alex-api-0.0.1-SNAPSHOT.jar ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DIR}/app/
|
||||
ssh ${REMOTE_USER}@${REMOTE_HOST} '
|
||||
cd ${REMOTE_DIR} &&
|
||||
docker compose down &&
|
||||
docker compose up -d --build
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
app/Dockerfile
Executable file
12
app/Dockerfile
Executable file
@ -0,0 +1,12 @@
|
||||
# 使用轻量级 OpenJDK 运行环境作为基础镜像
|
||||
FROM openjdk:8-jdk
|
||||
# 作者信息(可选)
|
||||
LABEL maintainer="2604434353@qq.com"
|
||||
# 创建工作目录
|
||||
WORKDIR /app
|
||||
# 复制 jar 包到容器中
|
||||
COPY alex-api-0.0.1-SNAPSHOT.jar app.jar
|
||||
# 开放容器端口
|
||||
EXPOSE 8888
|
||||
# 启动命令
|
||||
ENTRYPOINT ["java", "-jar", "app.jar"]
|
BIN
app/alex-api-0.0.1-SNAPSHOT.jar
Executable file
BIN
app/alex-api-0.0.1-SNAPSHOT.jar
Executable file
Binary file not shown.
15
bin/post-steps.sh
Executable file
15
bin/post-steps.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
PORT=8888
|
||||
JAR_PATH="/home/alex/alex-api/app/alex-api-0.0.1-SNAPSHOT.jar"
|
||||
LOG_PATH="/home/alex/alex-api/logs/alex-api.log"
|
||||
|
||||
# 检测端口是否被占用
|
||||
if netstat -tuln | grep -q ":$PORT"; then
|
||||
echo "Port $PORT is already in use. Not starting application."
|
||||
exit 0
|
||||
else
|
||||
echo "Port $PORT is free. Starting application..."
|
||||
nohup java -jar "$JAR_PATH" > "$LOG_PATH" 2>&1 &
|
||||
echo "Application started with PID $!"
|
||||
fi
|
13
bin/pre-steps.sh
Executable file
13
bin/pre-steps.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
pid=$(ps -ef | grep -w java | grep "alex-api-0.0.1-SNAPSHOT.jar" | grep -v grep | awk '{print $2}')
|
||||
|
||||
echo "Found pid: $pid"
|
||||
|
||||
if [ -z "$pid" ]; then
|
||||
echo "Java application not running."
|
||||
else
|
||||
sudo kill -9 $pid
|
||||
echo "Java application (pid: $pid) stopping..."
|
||||
sleep 2
|
||||
fi
|
70
docker-compose.yml
Executable file
70
docker-compose.yml
Executable file
@ -0,0 +1,70 @@
|
||||
name: alex-api-docker
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
container_name: mysql
|
||||
restart: always
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ALEXzcz123456
|
||||
MYSQL_DATABASE: test_alex
|
||||
MYSQL_USER: alex
|
||||
MYSQL_PASSWORD: ALEXzcz123456
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- mysql-data:/var/lib/mysql
|
||||
networks:
|
||||
- alex-bridge-network
|
||||
|
||||
redis:
|
||||
image: redis:6
|
||||
container_name: redis
|
||||
command: redis-server --requirepass "ALEXzcz123456"
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
networks:
|
||||
- alex-bridge-network
|
||||
|
||||
alex-api:
|
||||
build:
|
||||
context: /home/alex/alex-api/app
|
||||
dockerfile: Dockerfile
|
||||
image: alex-api-image
|
||||
container_name: alex-api
|
||||
restart: always
|
||||
depends_on:
|
||||
- mysql
|
||||
- redis
|
||||
ports:
|
||||
- "8888:8888"
|
||||
networks:
|
||||
- alex-bridge-network
|
||||
|
||||
nginx:
|
||||
image: nginx:latest
|
||||
container_name: nginx
|
||||
restart: always
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- /etc/nginx/conf.d/alex-ui.conf:/etc/nginx/conf.d/alex-ui.conf
|
||||
- /var/www/alex-ui:/var/www/alex-ui
|
||||
- /var/log/nginx:/var/log/nginx
|
||||
depends_on:
|
||||
- alex-api
|
||||
networks:
|
||||
- alex-bridge-network
|
||||
|
||||
# 声明命名数据卷
|
||||
volumes:
|
||||
mysql-data:
|
||||
external: true # 使用已有的 mysql-data 卷,不创建新卷
|
||||
redis-data:
|
||||
external: true
|
||||
|
||||
# 创建自定义网络
|
||||
networks:
|
||||
alex-bridge-network:
|
||||
driver: bridge
|
45
logs/alex-api.log
Normal file
45
logs/alex-api.log
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
:: Spring Boot :: (v2.6.13)
|
||||
|
||||
2025-07-15 09:34:11.450 INFO 2719370 --- [ main] com.ctgu.alexapi.AlexApiApplication : Starting AlexApiApplication using Java 17.0.15 on server with PID 2719370 (/home/alex/alex-api/app/alex-api-0.0.1-SNAPSHOT.jar started by alex in /home/alex)
|
||||
2025-07-15 09:34:11.452 INFO 2719370 --- [ main] com.ctgu.alexapi.AlexApiApplication : The following 1 profile is active: "dev"
|
||||
2025-07-15 09:34:12.544 INFO 2719370 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
|
||||
2025-07-15 09:34:12.547 INFO 2719370 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
|
||||
2025-07-15 09:34:12.590 INFO 2719370 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20 ms. Found 0 Redis repository interfaces.
|
||||
2025-07-15 09:34:13.738 INFO 2719370 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8888 (http)
|
||||
2025-07-15 09:34:13.770 INFO 2719370 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
|
||||
2025-07-15 09:34:13.770 INFO 2719370 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.68]
|
||||
2025-07-15 09:34:13.950 INFO 2719370 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
|
||||
2025-07-15 09:34:13.950 INFO 2719370 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2362 ms
|
||||
_ _ |_ _ _|_. ___ _ | _
|
||||
| | |\/|_)(_| | |_\ |_)||_|_\
|
||||
/ |
|
||||
3.5.1
|
||||
2025-07-15 09:34:16.185 INFO 2719370 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8888 (http) with context path ''
|
||||
2025-07-15 09:34:16.204 INFO 2719370 --- [ main] com.ctgu.alexapi.AlexApiApplication : Started AlexApiApplication in 5.761 seconds (JVM running for 6.61)
|
||||
2025-07-15 09:45:02.685 INFO 2719370 --- [0.0-8888-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
|
||||
2025-07-15 09:45:02.686 INFO 2719370 --- [0.0-8888-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
|
||||
2025-07-15 09:45:02.687 INFO 2719370 --- [0.0-8888-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
|
||||
2025-07-15 09:45:02.907 INFO 2719370 --- [0.0-8888-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||
2025-07-15 09:45:03.268 INFO 2719370 --- [0.0-8888-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||
2025-07-15 10:55:24.202 INFO 2719370 --- [0.0-8888-exec-3] o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header
|
||||
Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
|
||||
|
||||
java.lang.IllegalArgumentException: Invalid character found in method name [0x030x000x00/*0xe00x000x000x000x000x00Cookie: ]. HTTP method names must be tokens
|
||||
at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:419) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:271) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.68.jar!/:na]
|
||||
at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
|
||||
|
133
pom.xml
Normal file
133
pom.xml
Normal file
@ -0,0 +1,133 @@
|
||||
<?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>
|
||||
<groupId>com.ctgu</groupId>
|
||||
<artifactId>alex-api</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>alex-api</name>
|
||||
<description>alex-api</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<spring-boot.version>2.6.13</spring-boot.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</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>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.19.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j2-impl</artifactId>
|
||||
<version>2.19.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<version>2.7.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>3.5.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<configuration>
|
||||
<mainClass>com.ctgu.alexapi.AlexApiApplication</mainClass>
|
||||
<!-- <skip>true</skip>-->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>repackage</id>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
15
src/main/java/com/ctgu/alexapi/AlexApiApplication.java
Normal file
15
src/main/java/com/ctgu/alexapi/AlexApiApplication.java
Normal file
@ -0,0 +1,15 @@
|
||||
package com.ctgu.alexapi;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@MapperScan("com.ctgu.alexapi.mapper")
|
||||
public class AlexApiApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AlexApiApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
42
src/main/java/com/ctgu/alexapi/config/RedisConfig.java
Normal file
42
src/main/java/com/ctgu/alexapi/config/RedisConfig.java
Normal file
@ -0,0 +1,42 @@
|
||||
package com.ctgu.alexapi.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
@Configuration
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
public RedisConnectionFactory redisConnectionFactory(RedisProperties redisProperties) {
|
||||
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
|
||||
config.setHostName(redisProperties.getHost());
|
||||
config.setPort(redisProperties.getPort());
|
||||
config.setPassword(redisProperties.getPassword());
|
||||
config.setDatabase(0);
|
||||
return new LettuceConnectionFactory(config);
|
||||
}
|
||||
|
||||
@Bean(name = "redisTemplate")
|
||||
public RedisTemplate<String, Object> redisTemplate(
|
||||
@Qualifier("redisConnectionFactory")RedisConnectionFactory redisConnectionFactory
|
||||
) {
|
||||
// 创建 RedisTemplate 对象
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||
|
||||
// 设置默认的序列化器(String 类型)
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setValueSerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
|
||||
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.ctgu.alexapi.controller;
|
||||
|
||||
import com.ctgu.alexapi.service.UsersService;
|
||||
import com.ctgu.alexapi.utils.ApiResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* @ClassName UserController
|
||||
* @Author Alex2
|
||||
* @Date 2025/7/2 14:43
|
||||
**/
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
public class UsersController {
|
||||
private final UsersService usersService;
|
||||
|
||||
@Autowired
|
||||
public UsersController(UsersService usersService) {
|
||||
this.usersService = usersService;
|
||||
}
|
||||
|
||||
// http://localhost:8888/api/users/getAllUser?pageNum=1&pageSize=10
|
||||
@GetMapping("/getAllUser")
|
||||
public ApiResult getAllUser(
|
||||
@RequestParam(value = "pageNum", defaultValue = "0", required = false) Integer pageNum,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10", required = false) Integer pageSize) {
|
||||
return usersService.getAllUser(pageNum, pageSize);
|
||||
}
|
||||
|
||||
// http://localhost:8888/api/users/1
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult getUserById(@PathVariable("id") Integer id) {
|
||||
return usersService.getUserById(id);
|
||||
}
|
||||
}
|
37
src/main/java/com/ctgu/alexapi/entity/UsersEntity.java
Normal file
37
src/main/java/com/ctgu/alexapi/entity/UsersEntity.java
Normal file
@ -0,0 +1,37 @@
|
||||
package com.ctgu.alexapi.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName t_users
|
||||
*/
|
||||
@TableName(value ="t_users")
|
||||
@Data
|
||||
public class UsersEntity implements Serializable {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@TableField(value = "username")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
@TableField(value = "password")
|
||||
private String password;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
18
src/main/java/com/ctgu/alexapi/mapper/UsersMapper.java
Normal file
18
src/main/java/com/ctgu/alexapi/mapper/UsersMapper.java
Normal file
@ -0,0 +1,18 @@
|
||||
package com.ctgu.alexapi.mapper;
|
||||
|
||||
import com.ctgu.alexapi.entity.UsersEntity;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author Alex2
|
||||
* @description 针对表【t_users】的数据库操作Mapper
|
||||
* @createDate 2025-07-02 14:37:56
|
||||
* @Entity com.ctgu.alexapi.entity.UsersEntity
|
||||
*/
|
||||
public interface UsersMapper extends BaseMapper<UsersEntity> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
17
src/main/java/com/ctgu/alexapi/service/UsersService.java
Normal file
17
src/main/java/com/ctgu/alexapi/service/UsersService.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.ctgu.alexapi.service;
|
||||
|
||||
import com.ctgu.alexapi.entity.UsersEntity;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.ctgu.alexapi.utils.ApiResult;
|
||||
|
||||
/**
|
||||
* @author Alex2
|
||||
* @description 针对表【t_users】的数据库操作Service
|
||||
* @createDate 2025-07-02 14:37:56
|
||||
*/
|
||||
public interface UsersService extends IService<UsersEntity> {
|
||||
|
||||
ApiResult getAllUser(Integer pageNum, Integer pageSize);
|
||||
|
||||
ApiResult getUserById(Integer id);
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.ctgu.alexapi.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.ctgu.alexapi.entity.UsersEntity;
|
||||
import com.ctgu.alexapi.service.UsersService;
|
||||
import com.ctgu.alexapi.mapper.UsersMapper;
|
||||
import com.ctgu.alexapi.utils.ApiResult;
|
||||
import com.ctgu.alexapi.utils.Tools;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.google.gson.Gson;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Alex2
|
||||
* @description 针对表【t_users】的数据库操作Service实现
|
||||
* @createDate 2025-07-02 14:37:56
|
||||
*/
|
||||
@Log4j2
|
||||
@Service
|
||||
public class UsersServiceImpl extends ServiceImpl<UsersMapper, UsersEntity>
|
||||
implements UsersService{
|
||||
|
||||
private static final String TAG = UsersServiceImpl.class.getSimpleName();
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
private static final String USER_CACHE_PREFIX = "user:";
|
||||
|
||||
@Override
|
||||
public ApiResult getAllUser(Integer pageNum, Integer pageSize) {
|
||||
PageHelper.startPage(pageNum, pageSize);
|
||||
List<UsersEntity> list = query().list();
|
||||
PageInfo<UsersEntity> pageInfo = new PageInfo<>(list, 5);
|
||||
return Tools.pageHelperResult(list, pageInfo, TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult getUserById(Integer userId) {
|
||||
String key = USER_CACHE_PREFIX + userId;
|
||||
// 1. 先从 Redis 取缓存
|
||||
String cachedUserJson = redisTemplate.opsForValue().get(key);
|
||||
if (cachedUserJson != null) {
|
||||
// 有缓存,反序列化后返回
|
||||
UsersEntity cachedUser = new Gson().fromJson(cachedUserJson, UsersEntity.class);
|
||||
log.debug("{}: 从缓存获取用户成功 = {}", TAG, cachedUser);
|
||||
return ApiResult.success("获取用户成功(缓存)", cachedUser);
|
||||
}
|
||||
|
||||
// 2. 缓存没命中,从数据库查
|
||||
UsersEntity usersEntity = lambdaQuery().eq(UsersEntity::getId, userId).one();
|
||||
if (usersEntity == null) {
|
||||
log.error("{}: 用户 Id = {} 不存在", TAG, userId);
|
||||
return ApiResult.error("用户不存在");
|
||||
}
|
||||
|
||||
// 3. 查到后写入缓存,设置过期时间,比如10分钟
|
||||
String userJson = new Gson().toJson(usersEntity);
|
||||
redisTemplate.opsForValue().set(key, userJson, 10, TimeUnit.MINUTES);
|
||||
|
||||
log.debug("{}: 获取用户成功 = {}", TAG, usersEntity);
|
||||
return ApiResult.success("获取用户成功", usersEntity);
|
||||
}
|
||||
}
|
100
src/main/java/com/ctgu/alexapi/utils/ApiResult.java
Normal file
100
src/main/java/com/ctgu/alexapi/utils/ApiResult.java
Normal file
@ -0,0 +1,100 @@
|
||||
package com.ctgu.alexapi.utils;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Optional;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
public class ApiResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8440958610795020343L;
|
||||
|
||||
public static final int CODE_SUCCESS = 200;
|
||||
public static final int CODE_ERROR = 500;
|
||||
public static final int CODE_WARNING = 501;
|
||||
public static final int CODE_NOT_PERMISSION = 403;
|
||||
public static final int CODE_NOE_LOGIN = 401;
|
||||
public static final int CODE_INVALID_REQUEST = 400;
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
private Object data;
|
||||
|
||||
// 构造方法
|
||||
public ApiResult(int code, String msg, Object data) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// 静态构造方法
|
||||
public static ApiResult success() {
|
||||
return new ApiResult(CODE_SUCCESS, null, null);
|
||||
}
|
||||
|
||||
public static ApiResult success(String msg) {
|
||||
return new ApiResult(CODE_SUCCESS, msg, null);
|
||||
}
|
||||
|
||||
public static ApiResult success(String msg, Object data) {
|
||||
return new ApiResult(CODE_SUCCESS, msg, data);
|
||||
}
|
||||
|
||||
public static ApiResult success(Object data) {
|
||||
return new ApiResult(CODE_SUCCESS, null, data);
|
||||
}
|
||||
|
||||
public static ApiResult error() {
|
||||
return new ApiResult(CODE_ERROR, "出错了", null);
|
||||
}
|
||||
|
||||
public static ApiResult error(String msg) {
|
||||
return new ApiResult(CODE_ERROR, msg, null);
|
||||
}
|
||||
|
||||
public static ApiResult error(String msg, Object data) {
|
||||
return new ApiResult(CODE_ERROR, msg, data);
|
||||
}
|
||||
|
||||
public static ApiResult notLogin() {
|
||||
return new ApiResult(CODE_NOE_LOGIN, "未登录,请先进行登录", null);
|
||||
}
|
||||
|
||||
public static ApiResult noPermissions() {
|
||||
return new ApiResult(CODE_NOT_PERMISSION, "权限不足", null);
|
||||
}
|
||||
|
||||
public static ApiResult build(int code, String msg) {
|
||||
return new ApiResult(code, msg, null);
|
||||
}
|
||||
|
||||
public static ApiResult getByBoolean(boolean b) {
|
||||
return b ? success() : error();
|
||||
}
|
||||
|
||||
public static ApiResult warning(String msg, Object data) {
|
||||
return new ApiResult(CODE_WARNING, msg, data);
|
||||
}
|
||||
|
||||
public static ApiResult warning(String msg) {
|
||||
return new ApiResult(CODE_WARNING, msg, null);
|
||||
}
|
||||
|
||||
public <T> Optional<T> getData(Class<T> clazz) {
|
||||
return Optional.ofNullable(clazz.cast(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ApiResult{" +
|
||||
"code=" + code +
|
||||
", msg='" + msg + '\'' +
|
||||
", data=" + (data != null ? data.toString() : "null") +
|
||||
'}';
|
||||
}
|
||||
}
|
16
src/main/java/com/ctgu/alexapi/utils/PageData.java
Normal file
16
src/main/java/com/ctgu/alexapi/utils/PageData.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.ctgu.alexapi.utils;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class PageData<T> {
|
||||
private Long totalNum; //总条数
|
||||
|
||||
private Integer totalPage; //总页数
|
||||
|
||||
private List<T> data; //数据
|
||||
}
|
46
src/main/java/com/ctgu/alexapi/utils/Tools.java
Normal file
46
src/main/java/com/ctgu/alexapi/utils/Tools.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.ctgu.alexapi.utils;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Log4j2
|
||||
public class Tools {
|
||||
public static <T> ApiResult pageHelperResult(List<T> list, PageInfo<T> pageInfo, String TAG) {
|
||||
if (list.isEmpty()) {
|
||||
log.debug("{} : 获取列表为空 = {}", TAG, Collections.emptyList());
|
||||
return ApiResult.success("获取列表为空", Collections.emptyList());
|
||||
}
|
||||
PageData.PageDataBuilder<T> builder = PageData.builder();
|
||||
log.debug("{} : 获取列表成功 = {}", TAG, list);
|
||||
return ApiResult.success("获取列表成功", builder
|
||||
.totalNum(pageInfo.getTotal())
|
||||
.totalPage(pageInfo.getPages())
|
||||
.data(list)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Author: Alex
|
||||
* @Description: 获取图片MD5
|
||||
*/
|
||||
public static String getMd5(String url) {
|
||||
if (url.contains("aliyuncs.com")) {
|
||||
int lastSlash = url.lastIndexOf('/');
|
||||
int lastDot = url.lastIndexOf('.');
|
||||
if (lastSlash != -1 && lastDot != -1 && lastDot > lastSlash) {
|
||||
return url.substring(lastSlash + 1, lastDot);
|
||||
}
|
||||
} else if (url.contains("/image/")) {
|
||||
int startIndex = url.lastIndexOf("/image/") + "/image/".length();
|
||||
int endIndex = url.indexOf("?", startIndex);
|
||||
if (endIndex == -1) {
|
||||
endIndex = url.length();
|
||||
}
|
||||
return url.substring(startIndex, endIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
12
src/main/resources/application-dev.yml
Normal file
12
src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,12 @@
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/test_alex?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: ALEXzcz123456
|
||||
redis:
|
||||
host: localhost
|
||||
password: ALEXzcz123456
|
||||
port: 6379
|
||||
database: 0
|
12
src/main/resources/application-prod.yml
Normal file
12
src/main/resources/application-prod.yml
Normal file
@ -0,0 +1,12 @@
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://117.72.202.202:3306/test_alex?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
username: alex
|
||||
password: ALEXzcz123456
|
||||
redis:
|
||||
host: 117.72.202.202
|
||||
password: ALEXzcz123456
|
||||
port: 6379
|
||||
database: 0
|
12
src/main/resources/application-test.yml
Normal file
12
src/main/resources/application-test.yml
Normal file
@ -0,0 +1,12 @@
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://117.72.202.202:3306/test_alex?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
username: alex
|
||||
password: ALEXzcz123456
|
||||
redis:
|
||||
host: 117.72.202.202
|
||||
password: ALEXzcz123456
|
||||
port: 6379
|
||||
database: 0
|
41
src/main/resources/application.yml
Normal file
41
src/main/resources/application.yml
Normal file
@ -0,0 +1,41 @@
|
||||
server:
|
||||
address: 0.0.0.0
|
||||
port: 8888
|
||||
spring:
|
||||
profiles:
|
||||
active: dev # 默认激活开发环境
|
||||
#配置mybatis
|
||||
mybatis:
|
||||
configuration:
|
||||
auto-mapping-behavior: full
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
type-aliases-package: com.anytrek.entity # 配置别名路径
|
||||
mapper-locations: classpath:mapper/*.xml # 配置 XML 文件位置
|
||||
#配置mybatis-plus
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
global-config:
|
||||
db-config:
|
||||
table-prefix: t_
|
||||
id-type: auto
|
||||
#配置分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
params: count=countSql
|
||||
reasonable: true
|
||||
supportMethodsArguments: true
|
||||
#配置日志
|
||||
logging:
|
||||
level:
|
||||
root: INFO #根日志配置,整个应用程序的默认日志级别为 INFO
|
||||
com.anytrek: DEBUG #com.anytrek 包下的类的日志级别设置为 DEBUG
|
||||
org.apache.ibatis: INFO #MyBatis 日志级别设置为 INFO
|
||||
com.zaxxer.hikari: INFO #HikariCP 的日志级别设置为 INFO
|
||||
org.springframework.web.socket: DEBUG
|
||||
org.springframework.web.socket.server.support: DEBUG
|
||||
org:
|
||||
springframework:
|
||||
integration: DEBUG
|
||||
messaging: DEBUG
|
16
src/main/resources/mapper/UsersMapper.xml
Normal file
16
src/main/resources/mapper/UsersMapper.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?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.ctgu.alexapi.mapper.UsersMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.ctgu.alexapi.entity.UsersEntity">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="username" column="username" jdbcType="VARCHAR"/>
|
||||
<result property="password" column="password" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,username,password
|
||||
</sql>
|
||||
</mapper>
|
13
src/test/java/com/ctgu/alexapi/AlexApiApplicationTests.java
Normal file
13
src/test/java/com/ctgu/alexapi/AlexApiApplicationTests.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.ctgu.alexapi;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class AlexApiApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user