AOP实战
设计一个数据库来存储和获取店铺下的员工信息,记录登陆日志,和修改操作 涉及几个步骤。以下是一个基本的数据库设计方案,假设你使用的是关系型数据库,如MySQL
设计一个数据库来存储和获取店铺下的员工信息涉及几个步骤。以下是一个基本的数据库设计方案,假设你使用的是关系型数据库,如MySQL或PostgreSQL。
获取店铺下的员工信息
### 数据库设计
1. **店铺表(`stores`)**:
- `store_id` (主键, 唯一标识店铺)
- `store_name` (店铺名称)
- `store_location` (店铺位置等其他信息)
```sql
CREATE TABLE stores (
store_id INT PRIMARY KEY AUTO_INCREMENT,
store_name VARCHAR(255) NOT NULL,
store_location VARCHAR(255)
);
```
2. **员工表(`employees`)**:
- `employee_id` (主键, 唯一标识员工)
- `first_name` (员工名)
- `last_name` (员工姓)
- `position` (员工职位)
- `store_id` (外键, 关联到店铺表)
```sql
CREATE TABLE employees (
employee_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
position VARCHAR(255),
store_id INT,
FOREIGN KEY (store_id) REFERENCES stores(store_id)
);
```
### 接口设计
1. **获取当前店铺下的员工接口**:
- **HTTP 方法**: GET
- **URL**: `/api/stores/{store_id}/employees`
- **参数**: `store_id` (店铺ID)
- **返回示例**:
```json
{
"employees": [
{
"employee_id": 1,
"first_name": "John",
"last_name": "Doe",
"position": "Manager"
},
{
"employee_id": 2,
"first_name": "Jane",
"last_name": "Smith",
"position": "Sales Associate"
}
]
}
```
- **示例 SQL 查询**:
```sql
SELECT employee_id, first_name, last_name, position
FROM employees
WHERE store_id = ?;
```
### 总结
- **`stores` 表** 存储店铺信息。
- **`employees` 表** 存储员工信息,并且通过 `store_id` 外键关联到店铺表。
- **接口** 通过店铺ID来获取所有员工的信息。
aop实战
在数据库中存储登录日志和操作记录通常需要两个表,一个用于记录用户登录信息,另一个用于记录操作日志。下面是如何设计这些表和实现相关功能的示例:
### 1. 数据库表设计
#### 登录日志表(`login_logs`)
```sql
CREATE TABLE login_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
login_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
success BOOLEAN NOT NULL,
ip_address VARCHAR(45)
);
```
- `id`: 主键,自增
- `username`: 用户名
- `login_time`: 登录时间
- `success`: 登录是否成功
- `ip_address`: 登录的IP地址
#### 操作记录表(`operation_logs`)
```sql
CREATE TABLE operation_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL,
operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
operation_details TEXT
);
```
- `id`: 主键,自增
- `username`: 用户名
- `operation_time`: 操作时间
- `operation_details`: 操作详细信息
### 2. 创建数据访问层(Repository)
使用Spring Data JPA或MyBatis等工具来处理数据访问。
#### 使用Spring Data JPA
##### 登录日志仓库接口
```java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface LoginLogRepository extends JpaRepository<LoginLog, Integer> {
}
```
##### 操作记录仓库接口
```java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface OperationLogRepository extends JpaRepository<OperationLog, Integer> {
}
```
#### 实体类
##### 登录日志实体类
```java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
@Entity
public class LoginLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private LocalDateTime loginTime;
private Boolean success;
private String ipAddress;
// Getters and Setters
}
```
##### 操作记录实体类
```java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
@Entity
public class OperationLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
private LocalDateTime operationTime;
private String operationDetails;
// Getters and Setters
}
```
### 3. 修改切面类以记录日志到数据库
在切面类中注入上述仓库,并在日志记录时保存数据到数据库。
#### 登录日志切面
```java
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoginLogAspect {
@Autowired
private LoginLogRepository loginLogRepository;
@AfterReturning(pointcut = "execution(* com.example.yourapp.service.UserService.login(..))", returning = "result")
public void logLogin(JoinPoint joinPoint, Object result) {
String username = (String) joinPoint.getArgs()[0];
boolean success = (result != null); // 判断登录是否成功
String ipAddress = ""; // 通过其他方式获取IP地址
LoginLog loginLog = new LoginLog();
loginLog.setUsername(username);
loginLog.setSuccess(success);
loginLog.setIpAddress(ipAddress);
loginLogRepository.save(loginLog);
}
}
```
#### 操作记录切面
```java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class OperationLogAspect {
@Autowired
private OperationLogRepository operationLogRepository;
@Before("execution(* com.example.yourapp.service.*.*(..))")
public void logOperation(JoinPoint joinPoint) {
String username = "someUser"; // 获取当前用户名,例如通过SecurityContextHolder
String operationDetails = "方法调用: " + joinPoint.getSignature().toShortString();
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
operationDetails += ", 参数: " + arg;
}
OperationLog operationLog = new OperationLog();
operationLog.setUsername(username);
operationLog.setOperationDetails(operationDetails);
operationLogRepository.save(operationLog);
}
}
```
### 总结
1. **设计数据库表**:为登录日志和操作记录创建适当的表。
2. **创建数据访问层**:使用Spring Data JPA或类似工具来处理数据库操作。
3. **实现切面类**:使用AOP切面在登录和操作时记录日志,并将日志保存到数据库中。
通过这种方式,你可以在数据库中存储详细的登录和操作记录,便于审计和分析。
获取ip地址
在Spring Boot应用中获取用户的IP地址可以通过不同的方式实现,具体取决于你的应用架构和环境。以下是一些常见的获取IP地址的方法:
### 1. 从HTTP请求中获取IP地址
如果你的应用是通过HTTP请求接收用户操作,通常可以通过`HttpServletRequest`获取客户端的IP地址。
#### 示例代码:
```java
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class IpAddressUtil {
@Autowired
private HttpServletRequest request;
public String getClientIpAddress() {
String remoteAddr = request.getRemoteAddr();
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
// X-Forwarded-For 头部可能包含多个IP地址,取第一个
return xForwardedFor.split(",")[0];
}
return remoteAddr;
}
}
```
### 2. 在AOP切面中获取IP地址
在AOP切面中获取IP地址,需要依赖`HttpServletRequest`。你可以通过Spring的依赖注入来实现这一点。
#### 示例代码:
```java
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class LoginLogAspect {
@Autowired
private LoginLogRepository loginLogRepository;
@Autowired
private HttpServletRequest request;
@AfterReturning(pointcut = "execution(* com.example.yourapp.service.UserService.login(..))", returning = "result")
public void logLogin(JoinPoint joinPoint, Object result) {
String username = (String) joinPoint.getArgs()[0];
boolean success = (result != null); // 判断登录是否成功
String ipAddress = getClientIpAddress();
LoginLog loginLog = new LoginLog();
loginLog.setUsername(username);
loginLog.setSuccess(success);
loginLog.setIpAddress(ipAddress);
loginLogRepository.save(loginLog);
}
private String getClientIpAddress() {
String remoteAddr = request.getRemoteAddr();
String xForwardedFor = request.getHeader("X-Forwarded-For");
if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
// X-Forwarded-For 头部可能包含多个IP地址,取第一个
return xForwardedFor.split(",")[0];
}
return remoteAddr;
}
}
```
### 3. 考虑代理和负载均衡器
如果你的应用运行在代理服务器或负载均衡器后面,`X-Forwarded-For` 头部通常会包含客户端的真实IP地址,而 `request.getRemoteAddr()` 可能返回代理服务器的IP地址。因此,你需要优先从 `X-Forwarded-For` 中获取IP地址。
### 4. 配置Spring Boot
确保你的Spring Boot应用允许获取HTTP请求的IP地址:
```properties
server.servlet.context-path=/your-context-path
```
### 总结
- **从HTTP请求中获取IP地址**:通过`HttpServletRequest`的`getRemoteAddr()`方法和`X-Forwarded-For`头部。
- **在AOP切面中获取IP地址**:可以在切面类中注入`HttpServletRequest`,然后使用上述方法获取IP地址。
- **考虑代理和负载均衡器**:优先使用`X-Forwarded-For`头部的IP地址。
这些方法可以帮助你在Spring Boot应用中获取用户的IP地址,并在日志记录等功能中使用。