参数校验
This commit is contained in:
parent
d84021f3db
commit
bce338ee19
7
pom.xml
7
pom.xml
|
@ -187,6 +187,13 @@
|
|||
<version>3.14.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--JSON 处理工具-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.62</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package com.greenorange.promotion.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
/**
|
||||
* 自定义注解记录系统操作日志
|
||||
*/
|
||||
//Target注解决定 MyLog 注解可以加在哪些成分上,如加在类身上,或者属性身上,或者方法身上等成分
|
||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
||||
//Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让 MyLog 这个注解的生命周期一直程序运行时都存在
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyLog {
|
||||
/**
|
||||
* 模块标题
|
||||
*/
|
||||
String title() default "";
|
||||
/**
|
||||
* 日志内容
|
||||
*/
|
||||
String content() default "";
|
||||
}
|
280
src/main/java/com/greenorange/promotion/aop/OperLogAspect.java
Normal file
280
src/main/java/com/greenorange/promotion/aop/OperLogAspect.java
Normal file
|
@ -0,0 +1,280 @@
|
|||
package com.greenorange.promotion.aop;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.greenorange.promotion.annotation.MyLog;
|
||||
import com.greenorange.promotion.model.entity.SysOperLog;
|
||||
import com.greenorange.promotion.service.log.SysOperLogService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.*;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 切面处理类,记录操作日志到数据库
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class OperLogAspect {
|
||||
|
||||
@Resource
|
||||
private SysOperLogService sysOperLogService;
|
||||
|
||||
// 为了记录方法的执行时间
|
||||
ThreadLocal<Long> startTime = new ThreadLocal<>();
|
||||
|
||||
|
||||
@Before("@annotation(myLog)")
|
||||
public void beforeMethod(JoinPoint joinPoint, MyLog myLog){
|
||||
startTime.set(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
|
||||
* @param joinPoint 切入点
|
||||
* @param result 返回结果
|
||||
*/
|
||||
@AfterReturning(value = "@annotation(myLog)", returning = "result")
|
||||
public void saveOperLog(JoinPoint joinPoint, MyLog myLog, Object result) {
|
||||
// 获取RequestAttributes
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
// 从获取RequestAttributes中获取HttpServletRequest的信息
|
||||
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
||||
try {
|
||||
// 从切面织入点处通过反射机制获取织入点处的方法
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
// 获取切入点所在的方法
|
||||
Method method = signature.getMethod();
|
||||
// 获取操作
|
||||
SysOperLog sysOperLog = new SysOperLog();
|
||||
sysOperLog.setTitle(myLog.title());//设置模块名称
|
||||
sysOperLog.setContent(myLog.content());//设置日志内容
|
||||
// 将入参转换成json
|
||||
String params = argsArrayToString(joinPoint.getArgs());
|
||||
// 获取请求的类名
|
||||
String className = joinPoint.getTarget().getClass().getName();
|
||||
// 获取请求的方法名
|
||||
String methodName = method.getName();
|
||||
methodName = className + "." + methodName + "()";
|
||||
sysOperLog.setMethod(methodName); //设置请求方法
|
||||
sysOperLog.setRequestMethod(request.getMethod());//设置请求方式
|
||||
sysOperLog.setRequestParam(params); // 请求参数
|
||||
sysOperLog.setResponseResult(JSON.toJSONString(result)); // 返回结果
|
||||
// 从request中取出账号
|
||||
String userAccount = (String) request.getAttribute("userAccount");
|
||||
sysOperLog.setOperName(userAccount); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
|
||||
String ip = getIp(request);
|
||||
sysOperLog.setIp(ip); // IP地址
|
||||
String ipLocation = getIpLocation(ip);
|
||||
sysOperLog.setIpLocation(ipLocation); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
|
||||
sysOperLog.setRequestUrl(request.getRequestURI()); // 请求URI
|
||||
sysOperLog.setOperTime(new Date()); // 时间
|
||||
sysOperLog.setStatus(0);//操作状态(0正常 1异常)
|
||||
Long takeTime = System.currentTimeMillis() - startTime.get();//记录方法执行耗时时间(单位:毫秒)
|
||||
sysOperLog.setTakeTime(takeTime);
|
||||
//插入数据库
|
||||
sysOperLogService.save(sysOperLog);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置操作异常切入点记录异常日志 扫描所有controller包下操作
|
||||
* 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
|
||||
*/
|
||||
@AfterThrowing(pointcut = "execution(* com.greenorange.promotion.controller..*.*(..))", throwing = "e")
|
||||
public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
|
||||
// 获取RequestAttributes
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
// 从获取RequestAttributes中获取HttpServletRequest的信息
|
||||
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
|
||||
|
||||
SysOperLog sysOperLog = new SysOperLog();
|
||||
try {
|
||||
// 从切面织入点处通过反射机制获取织入点处的方法
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
// 获取切入点所在的方法
|
||||
Method method = signature.getMethod();
|
||||
// 获取请求的类名
|
||||
String className = joinPoint.getTarget().getClass().getName();
|
||||
// 获取请求的方法名
|
||||
String methodName = method.getName();
|
||||
methodName = className + "." + methodName + "()";
|
||||
// 获取操作
|
||||
MyLog myLog = method.getAnnotation(MyLog.class);
|
||||
if (myLog != null) {
|
||||
sysOperLog.setTitle(myLog.title());//设置模块名称
|
||||
sysOperLog.setContent(myLog.content());//设置日志内容
|
||||
}
|
||||
// 将入参转换成json
|
||||
String params = argsArrayToString(joinPoint.getArgs());
|
||||
sysOperLog.setMethod(methodName); //设置请求方法
|
||||
sysOperLog.setRequestMethod(request.getMethod());//设置请求方式
|
||||
sysOperLog.setRequestParam(params); // 请求参数
|
||||
// 从request中取出账号
|
||||
String userAccount = (String) request.getAttribute("userAccount");
|
||||
sysOperLog.setOperName(userAccount); // 获取用户名(真实环境中,肯定有工具类获取当前登录者的账号或ID的,或者从token中解析而来)
|
||||
String ip = getIp(request);
|
||||
sysOperLog.setIp(ip); // IP地址
|
||||
String ipLocation = getIpLocation(ip);
|
||||
sysOperLog.setIpLocation(ipLocation); // IP归属地(真是环境中可以调用第三方API根据IP地址,查询归属地)
|
||||
sysOperLog.setRequestUrl(request.getRequestURI()); // 请求URI
|
||||
sysOperLog.setOperTime(new Date()); // 时间
|
||||
sysOperLog.setStatus(1);//操作状态(0正常 1异常)
|
||||
sysOperLog.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));//记录异常信息
|
||||
//插入数据库
|
||||
sysOperLogService.save(sysOperLog);
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换异常信息为字符串
|
||||
*/
|
||||
public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
|
||||
StringBuffer strbuff = new StringBuffer();
|
||||
for (StackTraceElement stet : elements) {
|
||||
strbuff.append(stet + "\n");
|
||||
}
|
||||
String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
|
||||
message = substring(message,0 ,2000);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数拼装
|
||||
*/
|
||||
private String argsArrayToString(Object[] paramsArray)
|
||||
{
|
||||
String params = "";
|
||||
if (paramsArray != null && paramsArray.length > 0) {
|
||||
for (Object o : paramsArray) {
|
||||
if (o != null) {
|
||||
try {
|
||||
Object jsonObj = JSON.toJSON(o);
|
||||
params += jsonObj.toString() + " ";
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return params.trim();
|
||||
}
|
||||
|
||||
//字符串截取
|
||||
public static String substring(String str, int start, int end) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
} else {
|
||||
if (end < 0) {
|
||||
end += str.length();
|
||||
}
|
||||
|
||||
if (start < 0) {
|
||||
start += str.length();
|
||||
}
|
||||
|
||||
if (end > str.length()) {
|
||||
end = str.length();
|
||||
}
|
||||
|
||||
if (start > end) {
|
||||
return "";
|
||||
} else {
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (end < 0) {
|
||||
end = 0;
|
||||
}
|
||||
return str.substring(start, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换request 请求参数
|
||||
* @param paramMap request获取的参数数组
|
||||
*/
|
||||
public Map<String, String> converMap(Map<String, String[]> paramMap) {
|
||||
Map<String, String> returnMap = new HashMap<>();
|
||||
for (String key : paramMap.keySet()) {
|
||||
returnMap.put(key, paramMap.get(key)[0]);
|
||||
}
|
||||
return returnMap;
|
||||
}
|
||||
|
||||
//根据HttpServletRequest获取访问者的IP地址
|
||||
public String getIp(HttpServletRequest request) {
|
||||
String ip = request.getHeader("x-forwarded-for");
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_CLIENT_IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getIpLocation(String ip) {
|
||||
try {
|
||||
// 发送请求到ip-api服务
|
||||
String url = "http://ip-api.com/json/" + ip + "?lang=zh-CN"; // 获取中文结果
|
||||
URL obj = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
|
||||
// 解析JSON返回结果
|
||||
JSONObject jsonResponse = JSONObject.parseObject(response.toString());
|
||||
String region = jsonResponse.getString("regionName"); // 省
|
||||
String city = jsonResponse.getString("city"); // 城市
|
||||
String country = jsonResponse.getString("country"); // 国家
|
||||
|
||||
return city + ", " + region + ", " + country; // 返回位置
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
}
|
|
@ -66,6 +66,8 @@ public class PermissionCheck {
|
|||
DecodedJWT decodedJWT = jwtUtils.verify(token);
|
||||
String userAccount = decodedJWT.getClaim("userAccount").asString();
|
||||
String userPassword = decodedJWT.getClaim("userPassword").asString();
|
||||
// 将账号存入request,用于记录日志
|
||||
request.setAttribute("userAccount", userAccount);
|
||||
// 打印token的过期时间
|
||||
Date expiresAt = decodedJWT.getExpiresAt();
|
||||
String formatExpiresAt = DateUtil.format(expiresAt, "yyyy-MM-dd HH:mm:ss");
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.greenorange.promotion.common.ResultUtils;
|
|||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.util.validation.ValidationError;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
|||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
@ -60,7 +63,6 @@ public class GlobalExceptionHandler {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// 处理业务异常
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public BaseResponse<?> businessExceptionHandler(BusinessException e) {
|
||||
|
@ -69,11 +71,14 @@ public class GlobalExceptionHandler {
|
|||
}
|
||||
|
||||
|
||||
// // 处理运行时异常
|
||||
// @ExceptionHandler(RuntimeException.class)
|
||||
// public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
|
||||
// log.error("RuntimeException", e);
|
||||
// return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
|
||||
// }
|
||||
// 处理 SQL 语法错误
|
||||
@ExceptionHandler(SQLException.class)
|
||||
public BaseResponse<?> handleSQLException(SQLException ex) {
|
||||
// 记录详细的 SQL 错误信息
|
||||
log.error("SQL 错误: " + ex.getMessage());
|
||||
return ResultUtils.error(ErrorCode.DATABASE_ERROR, "SQL语法错误,详细信息:" + ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package com.greenorange.promotion.mapper;
|
||||
|
||||
import com.greenorange.promotion.model.entity.SysOperLog;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 35880
|
||||
* @description 针对表【sys_oper_log(操作日志记录)】的数据库操作Mapper
|
||||
* @createDate 2025-05-02 20:24:46
|
||||
* @Entity com.greenorange.promotion.model.entity.SysOperLog
|
||||
*/
|
||||
public interface SysOperLogMapper extends BaseMapper<SysOperLog> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
package com.greenorange.promotion.model.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 java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 操作日志记录
|
||||
* @TableName sys_oper_log
|
||||
*/
|
||||
@TableName(value ="sys_oper_log")
|
||||
@Data
|
||||
public class SysOperLog implements Serializable {
|
||||
/**
|
||||
* 日志主键
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 模块标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 日志内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 请求方式
|
||||
*/
|
||||
private String requestMethod;
|
||||
|
||||
/**
|
||||
* 操作人员
|
||||
*/
|
||||
private String operName;
|
||||
|
||||
/**
|
||||
* 请求URL
|
||||
*/
|
||||
private String requestUrl;
|
||||
|
||||
/**
|
||||
* 请求IP地址
|
||||
*/
|
||||
private String ip;
|
||||
|
||||
/**
|
||||
* IP归属地
|
||||
*/
|
||||
private String ipLocation;
|
||||
|
||||
/**
|
||||
* 请求参数
|
||||
*/
|
||||
private String requestParam;
|
||||
|
||||
/**
|
||||
* 方法响应参数
|
||||
*/
|
||||
private String responseResult;
|
||||
|
||||
/**
|
||||
* 操作状态(0正常 1异常)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMsg;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private Date operTime;
|
||||
|
||||
/**
|
||||
* 方法执行耗时(单位:毫秒)
|
||||
*/
|
||||
private Long takeTime;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.greenorange.promotion.service.log;
|
||||
|
||||
import com.greenorange.promotion.model.entity.SysOperLog;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 35880
|
||||
* @description 针对表【sys_oper_log(操作日志记录)】的数据库操作Service
|
||||
* @createDate 2025-05-02 20:24:46
|
||||
*/
|
||||
public interface SysOperLogService extends IService<SysOperLog> {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.greenorange.promotion.service.log.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.greenorange.promotion.model.entity.SysOperLog;
|
||||
import com.greenorange.promotion.service.log.SysOperLogService;
|
||||
import com.greenorange.promotion.mapper.SysOperLogMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 35880
|
||||
* @description 针对表【sys_oper_log(操作日志记录)】的数据库操作Service实现
|
||||
* @createDate 2025-05-02 20:24:46
|
||||
*/
|
||||
@Service
|
||||
public class SysOperLogServiceImpl extends ServiceImpl<SysOperLogMapper, SysOperLog>
|
||||
implements SysOperLogService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
32
src/main/resources/mapper/SysOperLogMapper.xml
Normal file
32
src/main/resources/mapper/SysOperLogMapper.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?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.greenorange.promotion.mapper.SysOperLogMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.greenorange.promotion.model.entity.SysOperLog">
|
||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="content" column="content" jdbcType="VARCHAR"/>
|
||||
<result property="method" column="method" jdbcType="VARCHAR"/>
|
||||
<result property="requestMethod" column="requestMethod" jdbcType="VARCHAR"/>
|
||||
<result property="operName" column="operName" jdbcType="VARCHAR"/>
|
||||
<result property="requestUrl" column="requestUrl" jdbcType="VARCHAR"/>
|
||||
<result property="ip" column="ip" jdbcType="VARCHAR"/>
|
||||
<result property="ipLocation" column="ipLocation" jdbcType="VARCHAR"/>
|
||||
<result property="requestParam" column="requestParam" jdbcType="VARCHAR"/>
|
||||
<result property="responseResult" column="responseResult" jdbcType="VARCHAR"/>
|
||||
<result property="status" column="status" jdbcType="INTEGER"/>
|
||||
<result property="errorMsg" column="errorMsg" jdbcType="VARCHAR"/>
|
||||
<result property="operTime" column="operTime" jdbcType="TIMESTAMP"/>
|
||||
<result property="takeTime" column="takeTime" jdbcType="BIGINT"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,title,content,
|
||||
method,requestMethod,operName,
|
||||
requestUrl,ip,ipLocation,
|
||||
requestParam,responseResult,status,
|
||||
errorMsg,operTime,takeTime
|
||||
</sql>
|
||||
</mapper>
|
138
src/test/java/com/greenorange/promotion/Client.java
Normal file
138
src/test/java/com/greenorange/promotion/Client.java
Normal file
|
@ -0,0 +1,138 @@
|
|||
package com.greenorange.promotion;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
|
||||
// Command 接口
|
||||
interface Command {
|
||||
void execute(); // 执行命令
|
||||
void undo(); // 撤销命令
|
||||
}
|
||||
|
||||
// Receiver 类,厨师执行具体的菜品制作命令
|
||||
class Chef {
|
||||
public void makeBurger() {
|
||||
System.out.println("制作汉堡...");
|
||||
}
|
||||
|
||||
public void makeFriedRice() {
|
||||
System.out.println("制作炒饭...");
|
||||
}
|
||||
|
||||
public void makeFriedChicken() {
|
||||
System.out.println("制作炸鸡...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 具体命令类
|
||||
class MakeBurgerCommand implements Command {
|
||||
private Chef chef;
|
||||
|
||||
public MakeBurgerCommand(Chef chef) {
|
||||
this.chef = chef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
chef.makeBurger(); // 执行命令,制作汉堡
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
System.out.println("撤销汉堡制作命令...");
|
||||
}
|
||||
}
|
||||
|
||||
class MakeFriedRiceCommand implements Command {
|
||||
private Chef chef;
|
||||
|
||||
public MakeFriedRiceCommand(Chef chef) {
|
||||
this.chef = chef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
chef.makeFriedRice(); // 执行命令,制作炒饭
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
System.out.println("撤销炒饭制作命令...");
|
||||
}
|
||||
}
|
||||
|
||||
class MakeFriedChickenCommand implements Command {
|
||||
private Chef chef;
|
||||
|
||||
public MakeFriedChickenCommand(Chef chef) {
|
||||
this.chef = chef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
chef.makeFriedChicken(); // 执行命令,制作炸鸡
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
System.out.println("撤销炸鸡制作命令...");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 服务员类,接收并执行命令
|
||||
class Waiter {
|
||||
private Stack<Command> commandHistory = new Stack<>(); // 用栈来保存历史命令,方便撤销
|
||||
|
||||
public void takeOrder(Command command) {
|
||||
command.execute(); // 执行命令
|
||||
commandHistory.push(command); // 将命令存入历史记录
|
||||
}
|
||||
|
||||
public void undoLastOrder() {
|
||||
if (!commandHistory.isEmpty()) {
|
||||
Command lastCommand = commandHistory.pop(); // 获取并移除栈顶命令
|
||||
lastCommand.undo(); // 执行撤销操作
|
||||
} else {
|
||||
System.out.println("没有可撤销的命令!");
|
||||
}
|
||||
}
|
||||
|
||||
// 宏命令:一次性下多个菜品
|
||||
public void placeMultipleOrders(Command[] commands) {
|
||||
for (Command command : commands) {
|
||||
takeOrder(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 客户端模拟点餐过程
|
||||
public class Client {
|
||||
public static void main(String[] args) {
|
||||
// 创建厨师
|
||||
Chef chef = new Chef();
|
||||
|
||||
// 创建具体命令
|
||||
Command makeBurger = new MakeBurgerCommand(chef);
|
||||
Command makeFriedRice = new MakeFriedRiceCommand(chef);
|
||||
Command makeFriedChicken = new MakeFriedChickenCommand(chef);
|
||||
|
||||
// 创建服务员
|
||||
Waiter waiter = new Waiter();
|
||||
|
||||
// 用户下单
|
||||
waiter.takeOrder(makeBurger);
|
||||
waiter.takeOrder(makeFriedRice);
|
||||
|
||||
// 用户撤销上一条订单(炒饭)
|
||||
waiter.undoLastOrder();
|
||||
|
||||
// 用户一次性下多个菜品(宏命令)
|
||||
Command[] orders = {makeBurger, makeFriedChicken};
|
||||
waiter.placeMultipleOrders(orders);
|
||||
}
|
||||
}
|
||||
|
48
src/test/java/com/greenorange/promotion/IpDemo.java
Normal file
48
src/test/java/com/greenorange/promotion/IpDemo.java
Normal file
|
@ -0,0 +1,48 @@
|
|||
package com.greenorange.promotion;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
public class IpDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
getIpLocation("123.167.57.119");
|
||||
}
|
||||
public static String getIpLocation(String ip) {
|
||||
try {
|
||||
// 发送请求到ip-api服务
|
||||
String url = "http://ip-api.com/json/" + ip + "?lang=zh-CN"; // 获取中文结果
|
||||
URL obj = new URL(url);
|
||||
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuffer response = new StringBuffer();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
|
||||
// 解析JSON返回结果
|
||||
JSONObject jsonResponse = JSONObject.parseObject(response.toString());
|
||||
String country = jsonResponse.getString("country"); // 国家
|
||||
String region = jsonResponse.getString("regionName"); // 省
|
||||
String city = jsonResponse.getString("city"); // 城市
|
||||
System.out.println(jsonResponse);
|
||||
System.out.println(country + "-" + region + "省" + "-" + city);
|
||||
return country + "-" + region + "省" + "-" + city; // 返回位置
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "未知";
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user