pull/3/head
litingting 11 months ago
parent a645aca4a3
commit 2d09ecde65

@ -8,73 +8,96 @@ import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
/** /**
* CommonCacheUtilRedis
* JedisPoolWrapperJedisPoolRedisSnailmallException
* Spring@Component便Spring使
* @Author swg. * @Author swg.
* @Date 2019/1/1 15:03 * @Date 2019/1/1 15:03
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@Component @Component
// 该注解表明这个类是Spring框架中的一个组件Spring会自动扫描并将其纳入到容器管理中使其可以被其他需要使用的类进行依赖注入。
@Slf4j @Slf4j
// 使用lombok的@Slf4j注解自动生成一个名为log的日志记录对象方便在类中记录日志信息便于后续调试和查看与Redis交互过程中出现的问题情况。
public class CommonCacheUtil { public class CommonCacheUtil {
@Autowired @Autowired
// 使用Spring的依赖注入功能自动注入JedisPoolWrapper的实例通过它来获取JedisPool从而能够获取Jedis客户端连接到Redis服务器进行操作。
private JedisPoolWrapper jedisPoolWrapper; private JedisPoolWrapper jedisPoolWrapper;
/** /**
* key * keyRedis
*
* @param key Redis
* @param value RedisJSON
*/ */
public void cache(String key, String value) { public void cache(String key, String value) {
try { try {
JedisPool pool = jedisPoolWrapper.getJedisPool(); JedisPool pool = jedisPoolWrapper.getJedisPool();
if (pool != null) { if (pool!= null) {
try (Jedis Jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
Jedis.select(0); jedis.select(0);
Jedis.set(key, value); // 使用Jedis客户端将指定的键值对存储到Redis中默认存储到Redis的第0个数据库Redis可以有多个数据库通过select方法选择
jedis.set(key, value);
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("redis存值失败", e); log.error("redis存值失败", e);
// 如果在存储过程中出现异常记录错误日志并抛出SnailmallException异常提示“redis报错”由全局异常处理机制进行处理。
throw new SnailmallException("redis报错"); throw new SnailmallException("redis报错");
} }
} }
/** /**
* key * keyRedis
*
* @param key RedisRedis
* @return Redisnull
*/ */
public String getCacheValue(String key) { public String getCacheValue(String key) {
String value = null; String value = null;
try { try {
JedisPool pool = jedisPoolWrapper.getJedisPool(); JedisPool pool = jedisPoolWrapper.getJedisPool();
if (pool != null) { if (pool!= null) {
try (Jedis Jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
Jedis.select(0); jedis.select(0);
value = Jedis.get(key); // 使用Jedis客户端根据指定的键从Redis中获取对应的值默认从Redis的第0个数据库中查找。
value = jedis.get(key);
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("redis获取指失败", e); log.error("redis获取指失败", e);
// 如果在获取过程中出现异常记录错误日志并抛出SnailmallException异常提示“redis报错”由全局异常处理机制进行处理。
throw new SnailmallException("redis报错"); throw new SnailmallException("redis报错");
} }
return value; return value;
} }
/** /**
* key * keyRedis
*
* @param key Redis
* @param value RedisJSON
* @param expire Redis
* @return 10
*/ */
public long cacheNxExpire(String key, String value, int expire) { public long cacheNxExpire(String key, String value, int expire) {
long result = 0; long result = 0;
try { try {
JedisPool pool = jedisPoolWrapper.getJedisPool(); JedisPool pool = jedisPoolWrapper.getJedisPool();
if (pool != null) { if (pool!= null) {
try (Jedis jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
jedis.select(0); jedis.select(0);
// 先使用Jedis的setnx方法尝试设置键值对只有在键不存在时才会设置成功返回1若键已存在则设置失败返回0。这是一个原子操作。
result = jedis.setnx(key, value); result = jedis.setnx(key, value);
// 如果设置键值对成功即setnx返回1再使用expire方法设置该键对应的缓存数据的过期时间单位为秒。
jedis.expire(key, expire); jedis.expire(key, expire);
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("redis塞值和设置缓存时间失败", e); log.error("redis塞值和设置缓存时间失败", e);
// 如果在设置过程中出现异常记录错误日志并抛出SnailmallException异常提示“redis报错”由全局异常处理机制进行处理。
throw new SnailmallException("redis报错"); throw new SnailmallException("redis报错");
} }
@ -82,23 +105,24 @@ public class CommonCacheUtil {
} }
/** /**
* key * keyRedis
*
* @param key Redis
*/ */
public void delKey(String key) { public void delKey(String key) {
JedisPool pool = jedisPoolWrapper.getJedisPool(); JedisPool pool = jedisPoolWrapper.getJedisPool();
if (pool != null) { if (pool!= null) {
try (Jedis jedis = pool.getResource()) { try (Jedis jedis = pool.getResource()) {
jedis.select(0); jedis.select(0);
try { try {
// 使用Jedis客户端根据指定的键从Redis中删除对应的缓存数据默认从Redis的第0个数据库中删除。
jedis.del(key); jedis.del(key);
} catch (Exception e) { } catch (Exception e) {
log.error("从redis中删除失败", e); log.error("从redis中删除失败", e);
// 如果在删除过程中出现异常记录错误日志并抛出SnailmallException异常提示“redis报错”由全局异常处理机制进行处理。
throw new SnailmallException("redis报错"); throw new SnailmallException("redis报错");
} }
} }
} }
} }
}
}

@ -5,38 +5,57 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisPoolConfig;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
/** /**
* JedisPoolWrapperJedisPoolJedisPool便便JedisPoolRedis
* ParametersRedis@PostConstructJedisPoolJedisPool使
* RedisRedisRedis使
* @Author swg. * @Author swg.
* @Date 2019/1/1 15:00 * @Date 2019/1/1 15:00
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC redisredishash * @DESC redisredishash
*/ */
@Component @Component
// 该注解表明这个类是Spring框架中的一个组件Spring会自动扫描并将其纳入到容器管理中使其可以被其他需要使用的类进行依赖注入。
@Slf4j @Slf4j
// 使用lombok的@Slf4j注解自动生成一个名为log的日志记录对象方便在类中记录日志信息便于后续调试和查看与Redis连接池初始化等相关的情况。
public class JedisPoolWrapper { public class JedisPoolWrapper {
@Autowired @Autowired
// 使用Spring的依赖注入功能自动注入Parameters对象该对象应该包含了如Redis的最大连接数、最大空闲连接数、最大等待时间等配置参数相关信息用于构建JedisPool。
private Parameters parameters; private Parameters parameters;
private JedisPool jedisPool = null; private JedisPool jedisPool = null;
/**
* @PostConstruct
* JedisPoolParametersJedisPool使JedisRedis
*/
@PostConstruct @PostConstruct
public void init(){ public void init() {
try { try {
JedisPoolConfig config = new JedisPoolConfig(); JedisPoolConfig config = new JedisPoolConfig();
// 设置JedisPool中最大的连接总数从Parameters对象中获取对应的配置参数用于控制同时可以从连接池获取的Jedis客户端的最大数量避免过多连接导致资源耗尽等问题。
config.setMaxTotal(parameters.getRedisMaxTotal()); config.setMaxTotal(parameters.getRedisMaxTotal());
// 设置JedisPool中最大的空闲连接数从Parameters对象中获取对应的配置参数空闲连接是指在连接池中暂时未被使用的连接合理设置可提高连接复用效率。
config.setMaxIdle(parameters.getRedisMaxIdle()); config.setMaxIdle(parameters.getRedisMaxIdle());
// 设置获取连接时的最大等待时间单位为毫秒从Parameters对象中获取对应的配置参数当连接池中的连接都被占用时新的获取连接请求会等待超过该时间则抛出异常避免长时间阻塞。
config.setMaxWaitMillis(parameters.getRedisMaxWaitMillis()); config.setMaxWaitMillis(parameters.getRedisMaxWaitMillis());
jedisPool = new JedisPool(config,parameters.getRedisHost(),parameters.getRedisPort(),2000,"xxx"); // 创建JedisPool对象传入配置信息、Redis服务器的主机地址、端口号以及连接超时时间这里设置为2000毫秒和密码示例中密码为"xxx",实际中应替换为真实密码)等参数,
// 这样就构建好了一个可以连接到指定Redis服务器的连接池对象后续可以通过它获取Jedis客户端进行Redis操作。
jedisPool = new JedisPool(config, parameters.getRedisHost(), parameters.getRedisPort(), 2000, "xxx");
log.info("【初始化redis连接池成功】"); log.info("【初始化redis连接池成功】");
}catch (Exception e){ } catch (Exception e) {
log.error("【初始化redis连接池失败】",e); log.error("【初始化redis连接池失败】", e);
} }
} }
/**
* JedisPool使JedisPool
* JedisRedis
* @return JedisPoolinitjedisPoolnullnull
*/
public JedisPool getJedisPool() { public JedisPool getJedisPool() {
return jedisPool; return jedisPool;
} }
} }

@ -5,29 +5,43 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* Parameters使Spring@Valueapplication.propertiesapplication.yml
* 便使RedisZookeeper
* 使Lombok@DataGetterSetter便访
* @Author swg. * @Author swg.
* @Date 2019/1/1 14:27 * @Date 2019/1/1 14:27
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@Component @Component
// 该注解表明这个类是Spring框架中的一个组件Spring会自动扫描并将其纳入到容器管理中使其可以被其他需要使用的类进行依赖注入方便获取配置参数。
@Data @Data
// 使用Lombok的@Data注解会自动为类中的所有非静态、非final属性生成Getter、Setter方法同时还会生成toString、equals、hashCode等方法方便对配置参数对象进行操作和使用。
public class Parameters { public class Parameters {
/*****redis config start*******/ /*****redis config start*******/
// 使用Spring的@Value注解从配置文件中读取名为"redis.host"的配置项的值并将其注入到redisHost属性中该属性用于存储Redis服务器的主机地址方便后续连接Redis时使用。
@Value("${redis.host}") @Value("${redis.host}")
private String redisHost; private String redisHost;
// 使用Spring的@Value注解从配置文件中读取名为"redis.port"的配置项的值并将其注入到redisPort属性中该属性用于存储Redis服务器的端口号以便在创建连接时指定正确的端口进行通信。
@Value("${redis.port}") @Value("${redis.port}")
private int redisPort; private int redisPort;
// 此处可能存在属性名的配置错误通常max-idle应该对应MaxIdlemax-total对应MaxTotal但按照代码逻辑该属性用于从配置文件中读取名为"redis.max-idle"的配置项的值,
// 并注入到redisMaxTotal属性中本意可能是存储Redis连接池的最大空闲连接数相关参数需确认配置项与属性的正确对应关系
@Value("${redis.max-idle}") @Value("${redis.max-idle}")
private int redisMaxTotal; private int redisMaxTotal;
// 此处同样可能存在属性名的配置错误通常max-total应该对应MaxTotalmax-idle对应MaxIdle按照代码逻辑该属性用于从配置文件中读取名为"redis.max-total"的配置项的值,
// 并注入到redisMaxIdle属性中本意可能是存储Redis连接池的最大连接总数相关参数需确认配置项与属性的正确对应关系
@Value("${redis.max-total}") @Value("${redis.max-total}")
private int redisMaxIdle; private int redisMaxIdle;
// 使用Spring的@Value注解从配置文件中读取名为"redis.max-wait-millis"的配置项的值并将其注入到redisMaxWaitMillis属性中该属性用于存储获取Redis连接时的最大等待时间单位为毫秒
// 控制当连接池无可用连接时的等待时长,避免长时间阻塞。
@Value("${redis.max-wait-millis}") @Value("${redis.max-wait-millis}")
private int redisMaxWaitMillis; private int redisMaxWaitMillis;
/*****redis config end*******/ /*****redis config end*******/
/*****curator config start*******/ /*****curator config start*******/
// 使用Spring的@Value注解从配置文件中读取名为"zk.host"的配置项的值并将其注入到zkHost属性中该属性用于存储Zookeeper服务器的主机地址方便后续与Zookeeper进行交互时使用。
@Value("${zk.host}") @Value("${zk.host}")
private String zkHost; private String zkHost;
/*****curator config end*******/ /*****curator config end*******/
} }

@ -1,46 +1,89 @@
package com.njupt.swg.common.constants; package com.njupt.swg.common.constants;
/** /**
* ConstantsRedis
* 便使
* @Author swg. * @Author swg.
* @Date 2019/1/1 13:19 * @Date 2019/1/1 13:19
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
public class Constants { public class Constants {
/**自定义状态码 start**/ /**
* 便使
*/
/**
* HTTP200使
*/
public static final int RESP_STATUS_OK = 200; public static final int RESP_STATUS_OK = 200;
/**
* HTTP401访
*/
public static final int RESP_STATUS_NOAUTH = 401; public static final int RESP_STATUS_NOAUTH = 401;
/**
* HTTP500
*/
public static final int RESP_STATUS_INTERNAL_ERROR = 500; public static final int RESP_STATUS_INTERNAL_ERROR = 500;
/**
* HTTP400
*/
public static final int RESP_STATUS_BADREQUEST = 400; public static final int RESP_STATUS_BADREQUEST = 400;
/**自定义状态码 end**/ /**
*
*/
/***redis user相关的key以这个打头**/ /**
* RediskeytokenRedis便
*/
public static final String TOKEN_PREFIX = "user_"; public static final String TOKEN_PREFIX = "user_";
/** /**
* redis * RedisCacheExtimeRedis
*/ */
public interface RedisCacheExtime{ public interface RedisCacheExtime {
int REDIS_SESSION_EXTIME = 60 * 60 * 10;//30分钟 /**
* Redis60 * 60 * 10103010
* Redis
*/
int REDIS_SESSION_EXTIME = 60 * 60 * 10;
} }
/** 用户注册判断重复的参数类型 start **/ /**
* 使便
*/
/**
*
*/
public static final String EMAIL = "email"; public static final String EMAIL = "email";
/**
* 使
*/
public static final String USERNAME = "username"; public static final String USERNAME = "username";
/** 用户注册判断重复的参数类型 end **/ /**
*
*/
/** 用户角色 **/ /**
public interface Role{ * Role便
int ROLE_CUSTOME = 0;//普通用户 */
int ROLE_ADMIN = 1;//管理员用户 public interface Role {
/**
* 访
*/
int ROLE_CUSTOME = 0;
/**
*
*/
int ROLE_ADMIN = 1;
} }
/**用户注册分布式锁路径***/ /**
* 使线Zookeeper
*/
public static final String USER_REGISTER_DISTRIBUTE_LOCK_PATH = "/user_reg"; public static final String USER_REGISTER_DISTRIBUTE_LOCK_PATH = "/user_reg";
}
}

@ -1,6 +1,5 @@
package com.njupt.swg.common.exception; package com.njupt.swg.common.exception;
import com.njupt.swg.common.constants.Constants; import com.njupt.swg.common.constants.Constants;
import com.njupt.swg.common.resp.ServerResponse; import com.njupt.swg.common.resp.ServerResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -9,25 +8,50 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
/** /**
* `ExceptionHandlerAdvice` Spring
* 使 `@ControllerAdvice``@ResponseBody` `@Slf4j` `@ExceptionHandler`
*
*
* @Author swg. * @Author swg.
* @Date 2019/1/1 13:21 * @Date 2019/1/1 13:21
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@ControllerAdvice @ControllerAdvice
// `@ControllerAdvice` 注解表明这个类是一个全局的异常处理组件它可以对整个应用程序中的控制器Controller层抛出的异常进行统一处理。
@ResponseBody @ResponseBody
// `@ResponseBody` 注解表示该类中处理异常的方法返回的结果会直接作为响应体返回给客户端,而不是进行视图解析等操作,通常用于返回 JSON 格式等数据给客户端。
@Slf4j @Slf4j
// `@Slf4j` 注解使用了 Lombok 提供的日志功能,会自动生成一个名为 `log` 的日志记录对象,方便在类中记录异常相关的日志信息,便于后续排查问题。
public class ExceptionHandlerAdvice { public class ExceptionHandlerAdvice {
/**
* 使 `@ExceptionHandler(Exception.class)` `Exception`
* `Exception`
* 便
*
* 使 `Constants` `RESP_STATUS_INTERNAL_ERROR`
*
* @param e `Exception`
* @return `ServerResponse`
*/
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ServerResponse handleException(Exception e){ public ServerResponse handleException(Exception e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
return ServerResponse.createByErrorCodeMessage(Constants.RESP_STATUS_INTERNAL_ERROR,"系统异常,请稍后再试"); return ServerResponse.createByErrorCodeMessage(Constants.RESP_STATUS_INTERNAL_ERROR, "系统异常,请稍后再试");
} }
/**
* 使 `@ExceptionHandler(SnailmallException.class)` `SnailmallException`
* `SnailmallException`
* `e.getExceptionStatus()` `e.getMessage()`
*
*
* @param e `SnailmallException`
* @return `ServerResponse`
*/
@ExceptionHandler(SnailmallException.class) @ExceptionHandler(SnailmallException.class)
public ServerResponse handleException(SnailmallException e){ public ServerResponse handleException(SnailmallException e) {
log.error(e.getMessage(),e); log.error(e.getMessage(), e);
return ServerResponse.createByErrorCodeMessage(e.getExceptionStatus(),e.getMessage()); return ServerResponse.createByErrorCodeMessage(e.getExceptionStatus(), e.getMessage());
} }
}
}

@ -4,22 +4,43 @@ import com.njupt.swg.common.resp.ResponseEnum;
import lombok.Getter; import lombok.Getter;
/** /**
* `SnailmallException` `java.lang.RuntimeException`
* 使便
*
* @Author swg. * @Author swg.
* @Date 2019/1/1 13:18 * @Date 2019/1/1 13:18
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@Getter @Getter
public class SnailmallException extends RuntimeException{ // 使用 Lombok 的 `@Getter` 注解,会自动为类中的 `exceptionStatus` 属性生成对应的 `get` 方法,方便外部获取该异常状态码的值,遵循了 Java 的封装原则,同时简化了代码编写。
public class SnailmallException extends RuntimeException {
// 定义一个用于存储异常状态码的属性,初始值设置为从 `ResponseEnum.ERROR` 中获取的状态码,
// `ResponseEnum` 应该是一个枚举类,用于定义各种响应状态的枚举值,这里默认使用 `ERROR` 对应的状态码作为异常状态码的初始值,
// 意味着在没有显式指定异常状态码时,将采用这个默认值来表示异常情况。
private int exceptionStatus = ResponseEnum.ERROR.getCode(); private int exceptionStatus = ResponseEnum.ERROR.getCode();
public SnailmallException(String msg){ /**
* `SnailmallException` `msg`
* `RuntimeException` `msg` 使 `ResponseEnum.ERROR.getCode()`
* 使使
*
* @param msg 便
*/
public SnailmallException(String msg) {
super(msg); super(msg);
} }
public SnailmallException(int code,String msg){ /**
* `code` `msg`
* `RuntimeException` `msg` `code` `exceptionStatus`
*
*
* @param code 便
* @param msg `msg`
*/
public SnailmallException(int code, String msg) {
super(msg); super(msg);
exceptionStatus = code; exceptionStatus = code;
} }
}
}

@ -3,23 +3,44 @@ package com.njupt.swg.common.resp;
import lombok.Getter; import lombok.Getter;
/** /**
* `ResponseEnum`
* 便使
* 使
*
* @Author swg. * @Author swg.
* @Date 2018/12/31 20:15 * @Date 2018/12/31 20:15
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@Getter @Getter
// 使用 Lombok 的 `@Getter` 注解,会自动为枚举中的 `code` 和 `desc` 属性生成对应的获取方法,方便外部代码获取这些属性值,
// 这样其他类在需要使用返回状态的状态码或者描述信息时,可以直接调用相应的获取方法,遵循了 Java 的封装原则,同时减少了代码冗余。
public enum ResponseEnum { public enum ResponseEnum {
SUCCESS(0,"SUCCESS"), // 表示业务操作成功的枚举常量,状态码为 `0`,对应的描述信息为 `"SUCCESS"`,通常用于标识业务操作顺利完成的情况,
ERROR(1,"ERROR"), // 例如查询操作成功获取到了期望的数据、新增数据成功插入到数据库等场景下,可以使用该枚举常量来表示操作成功的返回状态。
ILLEGAL_ARGUMENTS(2,"ILLEGAL_ARGUMENTS"), SUCCESS(0, "SUCCESS"),
NEED_LOGIN(10,"NEED_LOGIN"); // 表示业务操作出现错误的枚举常量,状态码为 `1`,对应的描述信息为 `"ERROR"`,这是一个比较笼统的错误标识,
// 可用于一般性的业务操作失败情况,比如在执行某个业务逻辑时发生了未预期的异常、或者满足了某种错误条件但不需要细分具体错误类型时,可以使用该枚举常量返回给调用者表示操作失败。
ERROR(1, "ERROR"),
// 表示参数非法的枚举常量,状态码为 `2`,对应的描述信息为 `"ILLEGAL_ARGUMENTS"`,主要用于客户端传入的参数不符合要求的场景,
// 例如参数格式错误、缺少必要参数、参数取值超出合法范围等情况,服务端在进行参数校验后发现参数不合法时,就可以返回该枚举常量对应的状态来告知调用者参数存在问题。
ILLEGAL_ARGUMENTS(2, "ILLEGAL_ARGUMENTS"),
// 表示需要登录的枚举常量,状态码为 `10`,对应的描述信息为 `"NEED_LOGIN"`,用于提示客户端当前操作需要先进行登录认证的场景,
// 比如客户端尝试访问某些需要登录权限才能操作的接口,但却未提供有效的登录凭证时,服务端就可以返回该枚举常量对应的状态,告知客户端需要先登录再进行后续操作。
NEED_LOGIN(10, "NEED_LOGIN");
private int code; private int code;
private String desc; private String desc;
ResponseEnum(int code,String desc){ /**
*
* `SUCCESS``ERROR` `code` `desc`
*
* @param code 便
* @param desc 便
*/
ResponseEnum(int code, String desc) {
this.code = code; this.code = code;
this.desc = desc; this.desc = desc;
} }
} }

@ -5,75 +5,167 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serializable; import java.io.Serializable;
/** /**
* `ServerResponse`
* `T` 使 Jackson
* 便 `Serializable` 使
*
* @Author swg. * @Author swg.
* @Date 2018/12/31 20:11 * @Date 2018/12/31 20:11
* @CONTACT 317758022@qq.com * @CONTACT 317758022@qq.com
* @DESC * @DESC
*/ */
@Getter @Getter
// 使用 Lombok 的 `@Getter` 注解,会自动为类中的 `status`、`msg` 和 `data` 属性生成对应的 `get` 方法,方便外部获取这些属性的值,遵循了 Java 的封装原则,简化了代码编写。
@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
// 使用 Jackson 的 `@JsonSerialize` 注解,配置序列化时的行为,这里指定了只包含非 `null` 的属性进行序列化,
// 也就是说在将 `ServerResponse` 对象转换为 JSON 格式(例如返回给客户端时),如果 `msg` 或者 `data` 等属性为 `null`,则不会包含在序列化后的 JSON 数据中,减少不必要的数据传输。
public class ServerResponse<T> implements Serializable { public class ServerResponse<T> implements Serializable {
// 用于存储操作的状态码,通过与 `ResponseEnum` 枚举类中的状态码进行对比,可以判断操作是成功还是失败以及具体的状态类型,例如 `0` 表示成功等情况。
private int status; private int status;
// 用于存储提示消息,一般是对操作结果的文字描述,比如操作成功时可以是 "操作成功",失败时可以是具体的错误原因等,方便客户端理解服务端返回的结果含义。
private String msg; private String msg;
// 泛型属性,用于存储具体的业务数据内容,类型根据实际业务场景而定,可以是单个对象、对象列表或者其他复杂的数据结构等,比如查询用户信息时可以是 `User` 对象,查询用户列表时可以是 `List<User>` 类型的数据。
private T data; private T data;
public ServerResponse(){} public ServerResponse() {}
private ServerResponse(int status){ // 私有构造方法,接收一个状态码参数,用于创建只包含状态码的 `ServerResponse` 对象实例,通常在一些内部初始化或者特定场景下使用,
// 外部一般通过静态方法来创建完整的响应对象,该构造方法主要是为了代码复用和方便在类内部构建不同情况的对象。
private ServerResponse(int status) {
this.status = status; this.status = status;
} }
private ServerResponse(int status,String msg){
// 私有构造方法,接收状态码和提示消息两个参数,用于创建包含状态码和提示消息的 `ServerResponse` 对象实例,
// 方便在已知操作状态码和对应的提示消息时构建响应对象,比如在出现错误时,传入错误状态码和具体的错误消息来创建相应的返回对象。
private ServerResponse(int status, String msg) {
this.status = status; this.status = status;
this.msg = msg; this.msg = msg;
} }
private ServerResponse(int status,T data){
// 私有构造方法,接收状态码和业务数据两个参数,用于创建包含状态码和具体数据的 `ServerResponse` 对象实例,
// 常用于操作成功且有具体数据需要返回给客户端的场景,例如查询操作成功获取到了数据,就可以通过传入成功状态码和查询到的数据来构建响应对象。
private ServerResponse(int status, T data) {
this.status = status; this.status = status;
this.data = data; this.data = data;
} }
private ServerResponse(int status,String msg,T data){
// 私有构造方法,接收状态码、提示消息和业务数据三个参数,用于创建包含完整信息(状态码、提示消息、业务数据)的 `ServerResponse` 对象实例,
// 适用于需要详细反馈操作结果,既包含状态、提示又有具体数据的各种复杂场景,比如部分更新操作,成功时可以传入成功状态码、更新成功的提示以及更新后的数据等情况来构建返回对象。
private ServerResponse(int status, String msg, T data) {
this.status = status; this.status = status;
this.msg = msg; this.msg = msg;
this.data = data; this.data = data;
} }
/**
* 使 `@JsonIgnore` `ServerResponse` JSON
* `ResponseEnum.SUCCESS` `0`
* 便便
*
* @return `true` `false`
*/
@JsonIgnore @JsonIgnore
public boolean isSuccess(){ public boolean isSuccess() {
return this.status == ResponseEnum.SUCCESS.getCode(); return this.status == ResponseEnum.SUCCESS.getCode();
} }
/** /**
* * `ServerResponse` 便
*/ */
public static <T>ServerResponse<T> createBySuccess(){
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(),ResponseEnum.SUCCESS.getDesc()); /**
} * `ResponseEnum.SUCCESS.getDesc()` `ServerResponse`
public static <T>ServerResponse<T> createBySuccessMessage(String message){ * 使
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(),message); *
} * @param <T> 使
public static <T>ServerResponse<T> createBySuccess(T data){ * @return `ServerResponse`
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(),data); */
} public static <T> ServerResponse<T> createBySuccess() {
public static <T>ServerResponse<T> createBySuccess(String message,T data){ return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getDesc());
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(),message,data);
} }
/** /**
* * `ServerResponse`
* `message`
* "数据新增成功,已保存到数据库"
*
* @param <T>
* @param message
* @return `ServerResponse`
*/ */
public static <T>ServerResponse<T> createByError(){ public static <T> ServerResponse<T> createBySuccessMessage(String message) {
return new ServerResponse<>(ResponseEnum.ERROR.getCode(),ResponseEnum.ERROR.getDesc()); return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(), message);
} }
public static <T>ServerResponse<T> createByErrorMessage(String msg){
return new ServerResponse<>(ResponseEnum.ERROR.getCode(),msg); /**
* `ServerResponse`
* `data` `T`
* `User`
*
* @param <T>
* @param data `ServerResponse` `data`
* @return `ServerResponse`
*/
public static <T> ServerResponse<T> createBySuccess(T data) {
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(), data);
} }
public static <T>ServerResponse<T> createByErrorCodeMessage(int code,String msg){
return new ServerResponse<>(code,msg); /**
* `ServerResponse`
* `message` `data`
* "用户信息更新成功" `User`
*
* @param <T> `data`
* @param message
* @param data `ServerResponse` `data`
* @return `ServerResponse`
*/
public static <T> ServerResponse<T> createBySuccess(String message, T data) {
return new ServerResponse<>(ResponseEnum.SUCCESS.getCode(), message, data);
} }
/**
* `ServerResponse` 便
*/
/**
* `ResponseEnum.ERROR.getDesc()` `ServerResponse`
* 使使
*
* @param <T>
* @return `ServerResponse`
*/
public static <T> ServerResponse<T> createByError() {
return new ServerResponse<>(ResponseEnum.ERROR.getCode(), ResponseEnum.ERROR.getDesc());
}
} /**
* `ServerResponse`
* `msg`
* "参数不符合要求,请检查输入参数"
*
* @param <T>
* @param msg
* @return `ServerResponse`
*/
public static <T> ServerResponse<T> createByErrorMessage(String msg) {
return new ServerResponse<>(ResponseEnum.ERROR.getCode(), msg);
}
/**
* `ServerResponse`
* `code` `msg`
*
*
* @param <T>
* @param code 便
* @param msg
* @return `ServerResponse`
*/
public static <T> ServerResponse<T> createByErrorCodeMessage(int code, String msg) {
return new ServerResponse<>(code, msg);
}
}

@ -2,47 +2,63 @@ package com.njupt.swg.common.utils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** /**
* cookie * `CookieUtil` `Cookie` `Cookie` `Cookie` `Cookie`
* `Cookie` 便 `Cookie` 使
*
* @Slf4j `log` 便 `Cookie` 便 `Cookie`
*/ */
@Slf4j @Slf4j
public class CookieUtil { public class CookieUtil {
// 定义了一个静态的常量字符串,表示 `Cookie` 所属的域名,用于设置 `Cookie` 的作用域名范围,这里固定为 "oursnail.cn",意味着只有在该域名下的页面请求才会携带和使用此 `Cookie`。
private final static String COOKIE_DOMAIN = "oursnail.cn"; private final static String COOKIE_DOMAIN = "oursnail.cn";
// 定义了一个静态的常量字符串,用于表示存储登录相关信息的 `Cookie` 的名称,后续通过这个名称来识别和操作特定的登录 `Cookie`,固定为 "snailmall_login_token"。
private final static String COOKIE_NAME = "snailmall_login_token"; private final static String COOKIE_NAME = "snailmall_login_token";
/** /**
* cookie * `Cookie` `token` `Cookie`
* @param response *
* @param token * @param response `HttpServletResponse` `Cookie` 使 `Cookie`
* @param token `COOKIE_NAME` `Cookie`
*/ */
public static void writeLoginToken(HttpServletResponse response,String token){ public static void writeLoginToken(HttpServletResponse response, String token) {
Cookie ck = new Cookie(COOKIE_NAME,token); // 创建一个新的 `Cookie` 对象,传入 `COOKIE_NAME` 作为 `Cookie` 的名称,`token` 作为 `Cookie` 的值,以此来构建用于存储登录凭证的 `Cookie`。
Cookie ck = new Cookie(COOKIE_NAME, token);
// 设置 `Cookie` 的域名属性,使其作用范围限定在指定的域名 "oursnail.cn" 下,只有访问该域名下的页面时,浏览器才会自动携带这个 `Cookie` 发送请求。
ck.setDomain(COOKIE_DOMAIN); ck.setDomain(COOKIE_DOMAIN);
ck.setPath("/");//设值在根目录 // 设置 `Cookie` 的路径属性为根目录 "/",意味着在该域名下的所有页面请求都会携带这个 `Cookie`,如果设置为其他具体路径,则只有访问该路径及其子路径下的页面时才会携带。
ck.setHttpOnly(true);//不允许通过脚本访问cookie,避免脚本攻击 ck.setPath("/");
ck.setMaxAge(60*60*24*365);//一年,-1表示永久,单位是秒maxage不设置的话cookie就不会写入硬盘只会写在内存只在当前页面有效 // 设置 `Cookie` 的 `HttpOnly` 属性为 `true`,这是一种安全机制,使得客户端脚本(如 JavaScript无法访问该 `Cookie`可以有效避免跨站脚本攻击XSS等安全问题提高系统的安全性。
log.info("write cookieName:{},cookieValue:{}",ck.getName(),ck.getValue()); ck.setHttpOnly(true);
// 设置 `Cookie` 的最大存活时间,这里设置为 `60 * 60 * 24 * 365` 秒,即一年,表示该 `Cookie` 在客户端浏览器保存的有效期为一年,超过这个时间后,浏览器会自动删除该 `Cookie`。
// 如果设置为 `-1`,则表示永久有效(不过不同浏览器对于永久有效的处理方式可能略有差异),若不设置该属性(`maxAge` 为默认值),则 `Cookie` 不会写入硬盘,只会保存在内存中,仅在当前页面会话有效。
ck.setMaxAge(60 * 60 * 24 * 365);
log.info("write cookieName:{},cookieValue:{}", ck.getName(), ck.getValue());
// 将构建好并设置好属性的 `Cookie` 添加到 `HttpServletResponse` 的响应头中,发送给客户端浏览器,使得浏览器能够保存这个 `Cookie` 用于后续请求携带。
response.addCookie(ck); response.addCookie(ck);
} }
/** /**
* cookie * `Cookie` `Cookie` `COOKIE_NAME` `Cookie`
* @param request * `Cookie``token` `null` `Cookie`
* @return *
* @param request `HttpServletRequest` `Cookie` `Cookie`
* @return `String` `COOKIE_NAME` `Cookie` `token` `null`
*/ */
public static String readLoginToken(HttpServletRequest request){ public static String readLoginToken(HttpServletRequest request) {
// 通过 `HttpServletRequest` 的 `getCookies` 方法获取客户端发送过来的所有 `Cookie`,以数组形式返回,如果没有 `Cookie` 则返回 `null`。
Cookie[] cks = request.getCookies(); Cookie[] cks = request.getCookies();
if(cks != null){ if (cks!= null) {
for(Cookie ck:cks){ for (Cookie ck : cks) {
log.info("cookieName:{},cookieBValue:{}",ck.getName(),ck.getValue()); log.info("cookieName:{},cookieBValue:{}", ck.getName(), ck.getValue());
if(StringUtils.equals(ck.getName(),COOKIE_NAME)){ // 使用 `StringUtils` 的 `equals` 方法(该方法可以避免空指针异常等情况,进行安全的字符串比较)比较当前遍历到的 `Cookie` 的名称与预定义的 `COOKIE_NAME` 是否相等,
log.info("return cookieName:{},cookieBValue:{}",ck.getName(),ck.getValue()); // 如果相等,则说明找到了存储登录凭证的 `Cookie`,返回其值(即登录 `token`)。
if (StringUtils.equals(ck.getName(), COOKIE_NAME)) {
log.info("return cookieName:{},cookieBValue:{}", ck.getName(), ck.getValue());
return ck.getValue(); return ck.getValue();
} }
} }
@ -51,24 +67,29 @@ public class CookieUtil {
} }
/** /**
* * `Cookie` `Cookie` `COOKIE_NAME` `Cookie`
* @param request * `0` `Cookie`
* @param response *
* @param request `HttpServletRequest` `Cookie` 便 `Cookie`
* @param response `HttpServletResponse` `0` `Cookie` `Cookie`
*/ */
public static void delLoginToken(HttpServletRequest request,HttpServletResponse response){ public static void delLoginToken(HttpServletRequest request, HttpServletResponse response) {
Cookie[] cks = request.getCookies(); Cookie[] cks = request.getCookies();
if(cks != null){ if (cks!= null) {
for(Cookie ck:cks) { for (Cookie ck : cks) {
if(StringUtils.equals(ck.getName(),COOKIE_NAME)){ if (StringUtils.equals(ck.getName(), COOKIE_NAME)) {
// 找到名称为 `COOKIE_NAME` 的 `Cookie` 后,先设置其域名属性为预定义的 `COOKIE_DOMAIN`,确保域名范围的一致性,与写入 `Cookie` 时的设置相匹配。
ck.setDomain(COOKIE_DOMAIN); ck.setDomain(COOKIE_DOMAIN);
// 设置 `Cookie` 的路径属性为根目录 "/",同样与写入 `Cookie` 时的路径设置保持一致,确保能够正确地删除对应的 `Cookie`。
ck.setPath("/"); ck.setPath("/");
ck.setMaxAge(0);//0表示消除此cookie // 设置 `Cookie` 的最大存活时间为 `0`,这表示通知客户端浏览器立即删除该 `Cookie`,使其失效,不再携带和使用该 `Cookie` 进行后续请求。
log.info("del cookieName:{},cookieBValue:{}",ck.getName(),ck.getValue()); ck.setMaxAge(0);
log.info("del cookieName:{},cookieBValue:{}", ck.getName(), ck.getValue());
// 将设置好属性的 `Cookie`(有效期为 `0`)重新添加到 `HttpServletResponse` 的响应头中,发送给客户端,触发客户端执行删除该 `Cookie` 的操作。
response.addCookie(ck); response.addCookie(ck);
return; return;
} }
} }
} }
} }
}
}

@ -4,65 +4,116 @@ import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
/** /**
* `DateTimeUtil` `Date``String`
* `Joda-Time` 便
* `main`
*
* @DESC * @DESC
*/ */
public class DateTimeUtil { public class DateTimeUtil {
//joda-time // 使用 `Joda-Time` 库来处理时间相关操作,以下定义的是一个常量字符串,表示时间格式的标准模板,用于在没有显式指定格式时作为默认的日期时间字符串格式,方便统一格式化规则。
//str->Date
//Date->str
public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";
/**
* `Date` `Joda-Time` `Date`
public static Date strToDate(String dateTimeStr, String formatStr){ *
* @param dateTimeStr "2024-12-17 10:30:00" `formatStr`
* @param formatStr `dateTimeStr` "yyyy-MM-dd HH:mm:ss" `Date`
* @return `Date` `Date` `Joda-Time`
*/
public static Date strToDate(String dateTimeStr, String formatStr) {
// 根据传入的格式字符串创建 `DateTimeFormatter` 对象,它用于定义如何解析日期时间字符串,按照指定的格式模板来解析输入的字符串内容。
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr); DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(formatStr);
// 使用创建好的 `DateTimeFormatter` 对输入的日期时间字符串进行解析,得到 `DateTime` 对象,`DateTime` 是 `Joda-Time` 库中用于表示日期时间的核心类,提供了丰富的日期时间操作方法。
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
// 将 `DateTime` 对象转换为 `Java` 标准库中的 `Date` 对象并返回,以便在基于 `Java` 标准库的其他代码中使用该日期时间数据。
return dateTime.toDate(); return dateTime.toDate();
} }
public static String dateToStr(Date date,String formatStr){ /**
if(date == null){ * `Date` `Date` `null`
* `null` `Joda-Time`
*
* @param date `Date` `null` `null`
* @param formatStr "yyyy-MM-dd HH:mm:ss" `Date`
* @return `Date` `null` `StringUtils.EMPTY` `null`
*/
public static String dateToStr(Date date, String formatStr) {
if (date == null) {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
// 根据传入的 `Date` 对象创建 `DateTime` 对象,以便使用 `Joda-Time` 库的功能进行后续的格式化操作,`DateTime` 类提供了方便的方法将日期时间转换为不同格式的字符串。
DateTime dateTime = new DateTime(date); DateTime dateTime = new DateTime(date);
return dateTime.toString(formatStr); return dateTime.toString(formatStr);
} }
//固定好格式 /**
public static Date strToDate(String dateTimeStr){ * `STANDARD_FORMAT` "yyyy-MM-dd HH:mm:ss" `Date`
* 使
*
* @param dateTimeStr "yyyy-MM-dd HH:mm:ss"
* @return `Date` `Date` `Joda-Time`
*/
public static Date strToDate(String dateTimeStr) {
// 根据默认的标准格式创建 `DateTimeFormatter` 对象,用于解析输入的日期时间字符串。
DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT); DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(STANDARD_FORMAT);
// 使用创建好的 `DateTimeFormatter` 对输入的日期时间字符串进行解析,得到 `DateTime` 对象。
DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr); DateTime dateTime = dateTimeFormatter.parseDateTime(dateTimeStr);
// 将 `DateTime` 对象转换为 `Java` 标准库中的 `Date` 对象并返回。
return dateTime.toDate(); return dateTime.toDate();
} }
public static String dateToStr(Date date){ /**
if(date == null){ * `Date` `STANDARD_FORMAT` "yyyy-MM-dd HH:mm:ss"
* `Date` 使 `Date` `null`
*
* @param date `Date` `null` `null`
* @return `Date` `null` `StringUtils.EMPTY` `null` "yyyy-MM-dd HH:mm:ss"
*/
public static String dateToStr(Date date) {
if (date == null) {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
// 根据传入的 `Date` 对象创建 `DateTime` 对象,以便使用 `Joda-Time` 库的功能将其转换为默认格式的字符串。
DateTime dateTime = new DateTime(date); DateTime dateTime = new DateTime(date);
return dateTime.toString(STANDARD_FORMAT); return dateTime.toString(STANDARD_FORMAT);
} }
//Date -> 时间戳 /**
* `Date` 19701100:00:00 UTC `Date` `null`
* `null` `null` `Java` `SimpleDateFormat` "yyyy-MM-dd HH:mm:ss" `Date`
* `Date` `SimpleDateFormat` `parse` `Date`
* `Date` `ParseException`
*
* @param date `Date` `null` `null` `null`
* @return `Date` `null` `null` `null`19701100:00:00 UTC
* @throws ParseException 使 `SimpleDateFormat` `Date`
*/
public static Long dateToChuo(Date date) throws ParseException { public static Long dateToChuo(Date date) throws ParseException {
if(date == null){ if (date == null) {
return null; return null;
} }
SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.parse(String.valueOf(date)).getTime(); return format.parse(String.valueOf(date)).getTime();
} }
/**
* `main` `Java` `dateToChuo` `SimpleDateFormat` `Date`
* `dateToChuo` 使 `ParseException`
* 使 `JUnit``TestNG`
*
* @param args 使
* @throws ParseException `main` `dateToChuo` `ParseException`
*/
public static void main(String[] args) throws ParseException { public static void main(String[] args) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time="1970-01-06 11:45:55"; String time = "1970-01-06 11:45:55";
Date date = format.parse(time); Date date = format.parse(time);
System.out.print("Format To times:"+date.getTime()); System.out.print("Format To times:" + date.getTime());
} }
} }
Loading…
Cancel
Save