pull/3/head
litingting 9 months ago
parent 2d09ecde65
commit 737f3f3045

@ -104,6 +104,11 @@
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>backport-util-concurrent</groupId>
<artifactId>backport-util-concurrent</artifactId>
<version>3.1</version>
</dependency>
</dependencies>

@ -8,118 +8,152 @@ import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import java.io.IOException;
import java.text.SimpleDateFormat;
/**
* jackson
* `JsonUtil` `Jackson`
* `ObjectMapper`
* 便 `JSON` `Java`
* `null`
*
* @Slf4j `log` 便 `IOException` 便
*/
@Slf4j
public class JsonUtil {
// 创建一个静态的 `ObjectMapper` 对象,它是 `Jackson` 库中用于进行序列化和反序列化操作的核心类,后续所有的配置和转换操作都基于这个对象来进行。
private static ObjectMapper objectMapper = new ObjectMapper();
static {
//所有字段都列入进行转换
// 以下是对 `ObjectMapper` 对象进行一系列的配置操作,通过静态代码块在类加载时执行这些配置,确保整个应用程序中使用的 `ObjectMapper` 具有统一的序列化和反序列化行为。
// 设置序列化时包含所有字段,即无论字段是否为 `null`,都将其列入进行转换,通过指定 `JsonSerialize.Inclusion.ALWAYS`,使得在将 `Java` 对象转换为 `JSON` 字符串时,所有的对象属性都会参与序列化过程。
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);
//取消默认转换timestamp形式
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS,false);
//忽略空bean转json的错误
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS,false);
//统一时间的格式
// 取消默认将日期转换为时间戳形式的行为,配置 `SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS` 为 `false`
// 这样在序列化包含日期类型的对象时,会按照后续配置的日期格式(如通过 `setDateFormat` 方法指定的格式)进行序列化,而不是转换为时间戳数值。
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
// 忽略空 `bean`(即没有属性值的 `Java` 对象)转 `JSON` 的错误,配置 `SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS` 为 `false`
// 当尝试序列化一个没有属性值的对象时,不会抛出异常,而是正常返回相应的 `JSON` 表示(可能为空对象的 `JSON` 格式),提高了序列化操作的容错性。
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
// 统一时间的格式,通过创建 `SimpleDateFormat` 对象并传入 `DateTimeUtil.STANDARD_FORMAT`(这应该是项目中定义的统一的日期时间格式字符串,例如 "yyyy-MM-dd HH:mm:ss"
// 然后使用 `setDateFormat` 方法设置到 `ObjectMapper` 中,使得在序列化和反序列化日期类型数据时,都按照这个统一格式进行处理,保证日期格式的一致性。
objectMapper.setDateFormat(new SimpleDateFormat(DateTimeUtil.STANDARD_FORMAT));
//忽略json存在属性但是java对象不存在属性的错误
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,false);
// 忽略 `JSON` 中存在属性,但对应的 `Java` 对象不存在该属性的错误,配置 `DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES` 为 `false`
// 在将 `JSON` 字符串反序列化为 `Java` 对象时,如果 `JSON` 字符串中包含了 `Java` 对象中不存在的属性,不会抛出异常,只会忽略这些未知属性进行反序列化操作,增强了反序列化操作的兼容性。
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
*
* @param obj
* @param <T>
* @return
* `Java` `JSON`
* `null` `null` `null`使 `ObjectMapper`
* `String` `writeValueAsString` `JSON`
* `IOException` `null`
*
* @param obj `Java` `T` `Java` `POJO` `Jackson`
* @param <T> 使
* @return `JSON` `null` `IOException` `null` `JSON`
*/
public static <T> String obj2String(T obj){
if(obj == null){
public static <T> String obj2String(T obj) {
if (obj == null) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
return obj instanceof String? (String) obj : objectMapper.writeValueAsString(obj);
} catch (IOException e) {
log.warn("parse object to string error",e);
log.warn("parse object to string error", e);
return null;
}
}
/**
* 便
* @param obj
* @param <T>
* @return
* `obj2String` `Java` `JSON` 便
* `null` `null` `null` `String` `writerWithDefaultPrettyPrinter`
* 使 `writeValueAsString` `JSON` `IOException` `null`
*
* @param obj `Java` `T` `obj2String` `Jackson`
* @param <T> `obj2String`
* @return `JSON` `null` `IOException` `null` `JSON` 便
*/
public static <T> String obj2StringPretty(T obj){
if(obj == null){
public static <T> String obj2StringPretty(T obj) {
if (obj == null) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
return obj instanceof String? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (IOException e) {
log.warn("parse object to string error",e);
log.warn("parse object to string error", e);
return null;
}
}
/**
*
* @param str
* @param clazz
* @param <T>
* @return
* `JSON` `Java`
* `JSON` `StringUtils.isEmpty` `Java` `null` `null`
* `String`
* 使 `ObjectMapper` `readValue` `JSON` `Java` `IOException` `null`
*
* @param str `JSON` `Jackson` `Java`
* @param clazz `Java` `Class<T>` `JSON` `User.class` `User` `Jackson`
* @param <T> `clazz`
* @return `Java` `JSON` `null` `IOException` `null` `Java`
*/
public static <T> T String2Obj(String str,Class<T> clazz){
if(StringUtils.isEmpty(str) || clazz == null){
public static <T> T String2Obj(String str, Class<T> clazz) {
if (StringUtils.isEmpty(str) || clazz == null) {
return null;
}
try {
return clazz.equals(String.class)?(T)str:objectMapper.readValue(str,clazz);
return clazz.equals(String.class)? (T) str : objectMapper.readValue(str, clazz);
} catch (IOException e) {
log.warn("parse string to obj error",e);
log.warn("parse string to obj error", e);
return null;
}
}
/**
*
* @param str
* @param typeReference
* @param <T>
* @return
* `TypeReference` `JSON` `Java`
* `JSON` `TypeReference` `null` `null` `TypeReference` `String`
* 使 `ObjectMapper` `readValue` `TypeReference` `JSON` `Java`
* `IOException` `null`
*
* @param str `JSON` `Jackson` `TypeReference`
* @param typeReference `TypeReference` `List<User>` `Jackson`
* @param <T> `TypeReference`
* @return `Java` `JSON` `TypeReference` `null` `IOException` `null` `Java`
*/
public static <T> T Str2Obj(String str, TypeReference typeReference){
if(StringUtils.isEmpty(str) || typeReference == null){
public static <T> T Str2Obj(String str, TypeReference typeReference) {
if (StringUtils.isEmpty(str) || typeReference == null) {
return null;
}
try {
return (T) (typeReference.getType().equals(String.class)?str:objectMapper.readValue(str,typeReference));
return (T) (typeReference.getType().equals(String.class)? str : objectMapper.readValue(str, typeReference));
} catch (IOException e) {
log.warn("parse string to obj error",e);
log.warn("parse string to obj error", e);
return null;
}
}
/**
*
* @param str
* @param collectionClass
* @param elementClasses
* @param <T>
* @return
* `JavaType` `JSON` `Java`
* 使 `objectMapper.getTypeFactory().constructParametricType` `JavaType`
* 使 `ObjectMapper` `readValue` `JavaType` `JSON` `Java` `IOException` `null`
* `JSON` `List<User>` 使
*
* @param str `JSON` `Jackson` `JavaType`
* @param collectionClass `List.class``Set.class` `Jackson`
* @param elementClasses `User.class` `Jackson`
* @param <T> `JavaType`
* @return `Java` `IOException` `null` `Java` `JSON` `List<User>`
*/
public static <T> T Str2Obj(String str,Class<?> collectionClass,Class<?>... elementClasses){
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);
public static <T> T Str2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses) {
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
try {
return objectMapper.readValue(str,javaType);
return objectMapper.readValue(str, javaType);
} catch (IOException e) {
log.warn("parse string to obj error",e);
log.warn("parse string to obj error", e);
return null;
}
}

@ -3,9 +3,19 @@ package com.njupt.swg.common.utils;
import java.security.MessageDigest;
/**
* MD5
* `MD5Util` `MD5` `MD5`
* `MD5` 便 `UTF-8` `MD5`
* `main` `MD5`
*/
public class MD5Util {
/**
*
* `byteToHexString`
* `MD5` 使
*
* @param b `MD5` 便使
* @return
*/
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
@ -14,6 +24,15 @@ public class MD5Util {
return resultSb.toString();
}
/**
*
* `0` `256` `Java` `-128` `127` `0` `255`
* `16` `16` `hexDigits`
* `byteArrayToHexString`
*
* @param b 便
* @return `2` `0f``1a`
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
@ -24,11 +43,15 @@ public class MD5Util {
}
/**
* MD5
* `MD5`
* `resultString` `MessageDigest.getInstance` `MD5` `MessageDigest`
* 使 `resultString` `MD5` `byteArrayToHexString` `resultString`
* `UTF-8` `resultString` `MD5` `resultString` `resultString` `MD5`
* `catch`
*
* @param origin
* @param charsetname
* @return
* @param origin `MD5`
* @param charsetname "utf-8""GBK" `null` 使
* @return `MD5` `null`
*/
private static String MD5Encode(String origin, String charsetname) {
String resultString = null;
@ -44,16 +67,33 @@ public class MD5Util {
return resultString.toUpperCase();
}
/**
* `UTF-8` `MD5` 便 `MD5Encode` "utf-8"
* `UTF-8` `MD5`
* `MD5Encode`
*
* @param origin `MD5` `UTF-8`
* @return `UTF-8` `MD5` `MD5Encode` `null`
*/
public static String MD5EncodeUtf8(String origin) {
//这里可以加盐
return MD5Encode(origin, "utf-8");
}
/**
* `main` `Java` `MD5EncodeUtf8` "123456" `MD5EncodeUtf8` `MD5`
* 使 `JUnit``TestNG`
*
* @param args 使
*/
public static void main(String[] args) {
System.out.println(MD5EncodeUtf8("123456"));
}
/**
* `hexDigits` `0` `9` `a` `f`
* `byteToHexString`
*/
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
}

@ -9,26 +9,46 @@ import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* `ZkClient` `Zookeeper` `Curator`
* `Parameters` `CuratorFrameworkFactory` `CuratorFramework`
* 使 `@Bean` `Spring` 便使
* `Spring` 便 `Zookeeper` `Zookeeper`
*
* @Author swg.
* @Date 2019/1/1 17:57
* @CONTACT 317758022@qq.com
* @DESC zkcurator
*/
@Component
// 该注解表明这个类是 `Spring` 框架中的一个组件,`Spring` 会自动扫描并将其纳入到容器管理中,使得这个类可以参与依赖注入等 `Spring` 容器相关的操作。
public class ZkClient {
@Autowired
// 使用 `Spring` 的依赖注入功能,自动注入 `Parameters` 类的实例,通过 `Parameters` 可以获取到项目中关于 `Zookeeper` 的配置参数,比如 `Zookeeper` 服务器的主机地址等信息,用于后续构建 `Curator` 客户端。
private Parameters parameters;
/**
* `@Bean` `Spring` `Bean` `CuratorFramework` `Zookeeper`
* `Spring` `CuratorFramework` `Spring` 使 `Zookeeper`
*
* @return `CuratorFramework` `Zookeeper` 使
*/
@Bean
public CuratorFramework getZkClient(){
CuratorFrameworkFactory.Builder builder= CuratorFrameworkFactory.builder()
public CuratorFramework getZkClient() {
// 使用 `CuratorFrameworkFactory` 的 `builder` 方法创建一个构建器对象,通过这个构建器可以方便地设置各种创建 `CuratorFramework` 客户端所需的配置参数,逐步构建出符合需求的客户端实例。
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder()
// 设置要连接的 `Zookeeper` 服务器的连接字符串,通过从注入的 `Parameters` 实例中获取 `zkHost` 属性来获取 `Zookeeper` 服务器的主机地址信息,
// 连接字符串的格式通常类似于 "ip1:port1,ip2:port2,...",用于指定要连接的 `Zookeeper` 集群中的服务器节点地址列表。
.connectString(parameters.getZkHost())
// 设置连接超时时间,单位为毫秒,这里设置为 `3000` 毫秒,表示客户端尝试连接 `Zookeeper` 服务器时,如果在 `3000` 毫秒内还未成功建立连接,就认为连接超时,触发相应的超时处理逻辑。
.connectionTimeoutMs(3000)
// 设置重试策略,这里使用 `RetryNTimes` 策略,表示当连接 `Zookeeper` 出现问题时,会进行重试操作,最多重试 `5` 次,每次重试间隔 `10` 毫秒,
// 通过这种重试机制来增加客户端连接成功的概率,提高客户端在面对网络抖动等临时问题时的健壮性。
.retryPolicy(new RetryNTimes(5, 10));
// 通过构建器对象的 `build` 方法创建出最终的 `CuratorFramework` 客户端实例,此时实例已经包含了前面设置的连接字符串、连接超时时间以及重试策略等配置信息。
CuratorFramework framework = builder.build();
// 启动 `CuratorFramework` 客户端,使其开始尝试连接 `Zookeeper` 服务器,在启动后客户端会根据配置的参数进行连接操作以及后续的相关初始化工作,进入可使用状态,
// 可以通过这个客户端实例执行诸如创建节点、获取节点数据、设置分布式锁等各种与 `Zookeeper` 交互的操作。
framework.start();
return framework;
}
}

@ -21,182 +21,222 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* @Author swg.
* @Date 2019/1/1 13:12
* @CONTACT 317758022@qq.com
* @DESC POSTMAN
*/
//TODO 先全部开放GET请求
// 为该控制器类下的所有请求路径设置统一的前缀为 "user",方便对用户模块相关的接口进行统一管理和组织。
@RequestMapping("user")
// 表明这个类是一个RESTful风格的控制器其方法返回的数据会直接作为响应体返回通常以JSON等格式而不是进行视图解析等操作。
@RestController
// 使用Slf4j注解生成一个名为log的日志记录对象方便在类中记录与用户操作相关的日志信息。
@Slf4j
// 表示标识这个类是swagger的资源
// 表示标识这个类是swagger的资源用于生成接口文档通过value属性指定接口文档中的名称tags属性用于对接口进行分类标记。
@Api(value = "UserController", tags = {"用户服务接口"})
public class UserController {
// 通过Spring的依赖注入功能自动注入IUserService接口的实现类实例用于调用用户相关的业务逻辑方法。
@Autowired
private IUserService userService;
// 注入CommonCacheUtil实例用于操作缓存如在用户登录等操作中与缓存进行交互。
@Autowired
private CommonCacheUtil commonCacheUtil;
/**
* cookieredis
* key
*
* 1.
* 2. userServiceloginServerResponse<UserResVO>
* 3. sessionIdcookie便
* 4. redis30便
* 5.
*/
@ApiOperation(value="用户登陆", notes="输入用户名,密码,不能为空")
@ApiOperation(value = "用户登陆", notes = "输入用户名,密码,不能为空")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String"),
@ApiImplicitParam(name = "password", value = "用户密码", required = true, dataType = "String")
})
@RequestMapping("/login.do")
public ServerResponse<UserResVO> login(HttpSession session, HttpServletResponse response, String username, String password){
log.info("【用户{}开始登陆】",username);
ServerResponse<UserResVO> userVOServerResponse = userService.login(username,password);
if(userVOServerResponse.isSuccess()){
//登陆成功那么需要在redis中存储并且将代表用户的sessionId写到前端浏览器的cookie中
log.info("【用户{}cookie开始写入】",username);
CookieUtil.writeLoginToken(response,session.getId());
//写到redis中将用户信息序列化设置过期时间为30分钟
log.info("【用户{}redis开始写入】",username);
public ServerResponse<UserResVO> login(HttpSession session, HttpServletResponse response, String username, String password) {
// 记录用户开始登录的日志,方便后续排查问题,如查看登录失败的原因等。
log.info("【用户{}开始登陆】", username);
ServerResponse<UserResVO> userVOServerResponse = userService.login(username, password);
if (userVOServerResponse.isSuccess()) {
// 记录开始写入cookie的日志用于跟踪cookie写入操作是否正常。
log.info("【用户{} cookie开始写入】", username);
// 将用户的sessionId写入cookie使浏览器保存该cookie用于后续请求识别用户登录状态。
CookieUtil.writeLoginToken(response, session.getId());
// 记录开始写入redis的日志便于监控redis写入操作的情况。
log.info("【用户{} redis开始写入】", username);
// 将用户信息序列化后存入redis缓存设置过期时间为30分钟提高后续获取用户信息的效率。
commonCacheUtil.cacheNxExpire(session.getId(), JsonUtil.obj2String(userVOServerResponse.getData()), Constants.RedisCacheExtime.REDIS_SESSION_EXTIME);
}
log.info("【用户{}登陆成功】",username);
// 记录用户登录成功的日志,完整记录登录操作过程。
log.info("【用户{}登陆成功】", username);
return userVOServerResponse;
}
/**
*
*
* 1.
* 2. userServiceregister使
* 3.
*/
@ApiOperation(value="创建用户", notes="根据User对象创建用户")
@ApiOperation(value = "创建用户", notes = "根据User对象创建用户")
@ApiImplicitParam(name = "user", value = "用户详细实体user", required = true, dataType = "User")
@RequestMapping("/register.do")
public ServerResponse register(User user){
public ServerResponse register(User user) {
// 记录开始注册的日志,有助于排查注册过程中出现的问题,如用户名或邮箱重复等情况。
log.info("【开始注册】");
//这里模拟高并发的注册场景,防止用户名字注册重复,所以需要加上分布式锁
// 这里模拟高并发的注册场景,防止用户名字注册重复,所以需要加上分布式锁调用userService的register方法进行实际注册操作。
ServerResponse response = userService.register(user);
// 记录用户注册成功的日志,方便监控注册操作的整体情况。
log.info("【用户注册成功】");
return response;
}
/**
*
*
* 1.
* 2. userServicecheckValid
* 3.
*/
@ApiOperation(value="验证用户名和邮箱是否重复", notes="用户名和邮箱都不能用已经存在的")
@ApiOperation(value = "验证用户名和邮箱是否重复", notes = "用户名和邮箱都不能用已经存在的")
@ApiImplicitParams({
@ApiImplicitParam(name = "str", value = "输入参数", required = true, dataType = "String"),
@ApiImplicitParam(name = "type", value = "参数类型", required = true, dataType = "String")
})
@RequestMapping("/check_valid.do")
public ServerResponse checkValid(@RequestParam("str") String str,
@RequestParam("type") String type){
@RequestParam("type") String type) {
// 记录开始验证用户名和邮箱是否重复的日志,方便后续查看验证操作的执行情况。
log.info("【开始验证用户名和邮箱是否重复】");
ServerResponse response = userService.checkValid(str,type);
ServerResponse response = userService.checkValid(str, type);
return response;
}
/**
*
* cookieoursnai.cnhosts127.0.0.1 oursnail.cn
* loginGEThttp://oursnail.cn:8081/user/login.do?username=admin&password=123456
* tokenhttp://oursnail.cn:8081/user/get_user_info.do
*
* 1. token
* 2. token
* 3. UseruserServicegetUserInfoFromDB
* 4.
*/
@ApiOperation(value="获取用户个人信息", notes="登陆状态下获取")
@ApiOperation(value = "获取用户个人信息", notes = "登陆状态下获取")
@RequestMapping("/get_user_info.do")
public ServerResponse getUserInfo(HttpServletRequest request){
public ServerResponse getUserInfo(HttpServletRequest request) {
// 从请求中读取登录token用于判断用户是否登录。
String loginToken = CookieUtil.readLoginToken(request);
if(StringUtils.isEmpty(loginToken)){
if (StringUtils.isEmpty(loginToken)) {
// 记录用户未登录的日志,方便排查问题,如用户未登录却尝试获取信息的情况。
log.info("【用户未登录,无法获取当前用户信息】");
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
// 从缓存中获取用户信息字符串,若为空则表示用户未登录或缓存信息丢失等情况。
String userStr = commonCacheUtil.getCacheValue(loginToken);
if(userStr == null){
if (userStr == null) {
// 记录用户未登录的日志,可能是缓存问题导致无法获取用户信息。
log.info("【用户未登录,无法获取当前用户信息】");
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
User currentUser = JsonUtil.Str2Obj(userStr,User.class);
// 将用户信息字符串反序列化为User对象以便后续获取详细信息。
User currentUser = JsonUtil.Str2Obj(userStr, User.class);
UserResVO userResVO = userService.getUserInfoFromDB(currentUser.getId());
return ServerResponse.createBySuccess("登陆用户获取自身信息成功",userResVO);
return ServerResponse.createBySuccess("登陆用户获取自身信息成功", userResVO);
}
/**
*
*
* 1.
* 2. userServicegetQuestionByUsername
* 3.
*/
@ApiOperation(value="根据用户名去拿到对应的问题", notes="忘记密码时首先根据用户名去获取设置的问题")
@ApiOperation(value = "根据用户名去拿到对应的问题", notes = "忘记密码时首先根据用户名去获取设置的问题")
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String")
@RequestMapping("/forget_get_question.do")
public ServerResponse forgetGetQuestion(String username){
log.info("【用户{}忘记密码,点击忘记密码输入用户名】",username);
public ServerResponse forgetGetQuestion(String username) {
// 记录用户忘记密码并进行获取问题操作的日志,方便后续排查忘记密码流程中的问题,如用户名不存在等情况。
log.info("【用户{}忘记密码,点击忘记密码输入用户名】", username);
ServerResponse response = userService.getQuestionByUsername(username);
return response;
}
/**
*
*
* 1.
* 2. userServicecheckAnswer
* 3.
*/
@ApiOperation(value="校验答案是否正确", notes="忘记密码时输入正确的用户名之后就可以获取到问题,此时就可以输入答案")
@ApiOperation(value = "校验答案是否正确", notes = "忘记密码时输入正确的用户名之后就可以获取到问题,此时就可以输入答案")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String"),
@ApiImplicitParam(name = "question", value = "设置的问题", required = true, dataType = "String"),
@ApiImplicitParam(name = "answer", value = "提交的答案", required = true, dataType = "String")
})
@RequestMapping("/forget_check_answer.do")
public ServerResponse forgetCheckAnswer(String username,String question,String answer){
log.info("【用户{}忘记密码,提交问题答案】",username);
ServerResponse response = userService.checkAnswer(username,question,answer);
public ServerResponse forgetCheckAnswer(String username, String question, String answer) {
// 记录用户忘记密码并提交答案进行校验的日志,有助于排查忘记密码答案校验过程中的问题,如答案错误等情况。
log.info("【用户{}忘记密码,提交问题答案】", username);
ServerResponse response = userService.checkAnswer(username, question, answer);
return response;
}
/**
*
* token
* 1. token
* 2. userServiceforgetResetPasswdtokentoken
* 3.
*/
@ApiOperation(value="忘记密码的重置密码", notes="输入新的密码要进行token的校验")
@ApiOperation(value = "忘记密码的重置密码", notes = "输入新的密码要进行token的校验")
@ApiImplicitParams({
@ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String"),
@ApiImplicitParam(name = "passwordNew", value = "新密码", required = true, dataType = "String"),
@ApiImplicitParam(name = "forgetToken", value = "前端保存的token", required = true, dataType = "String")
})
@RequestMapping("/forget_reset_password.do")
public ServerResponse forgetResetPasswd(String username,String passwordNew,String forgetToken){
log.info("【用户{}忘记密码,输入新密码】",username);
ServerResponse response = userService.forgetResetPasswd(username,passwordNew,forgetToken);
public ServerResponse forgetResetPasswd(String username, String passwordNew, String forgetToken) {
// 记录用户忘记密码并进行重置密码操作的日志,方便后续排查忘记密码重置过程中的问题,如新密码不符合要求等情况。
log.info("【用户{}忘记密码,输入新密码】", username);
ServerResponse response = userService.forgetResetPasswd(username, passwordNew, forgetToken);
return response;
}
/**
*
*
* 1. cookietoken
* 2. tokenredis
* 3. User
* 4. userServiceresetPasswdID
* 5.
*/
@ApiOperation(value="登陆状态的重置密码", notes="登陆的时候只需要输入老的密码和新密码即可")
@ApiOperation(value = "登陆状态的重置密码", notes = "登陆的时候只需要输入老的密码和新密码即可")
@ApiImplicitParams({
@ApiImplicitParam(name = "passwordOld", value = "老密码", required = true, dataType = "String"),
@ApiImplicitParam(name = "passwordNew", value = "新密码", required = true, dataType = "String")
})
@RequestMapping("/reset_password.do")
public ServerResponse resetPasswd(String passwordOld,String passwordNew,HttpServletRequest request){
//1.读取cookie
public ServerResponse resetPasswd(String passwordOld, String passwordNew, HttpServletRequest request) {
// 1.读取cookie
String loginToken = CookieUtil.readLoginToken(request);
if(StringUtils.isEmpty(loginToken)){
if (StringUtils.isEmpty(loginToken)) {
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
//2.从redis中获取用户信息
// 2.从redis中获取用户信息
String userStr = commonCacheUtil.getCacheValue(loginToken);
if(userStr == null){
if (userStr == null) {
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
User currentUser = JsonUtil.Str2Obj(userStr,User.class);
log.info("【用户{}重置密码】",currentUser);
User currentUser = JsonUtil.Str2Obj(userStr, User.class);
// 记录用户登录状态下重置密码的日志,有助于排查登录用户重置密码过程中的问题,如老密码错误等情况。
log.info("【用户{}重置密码】", currentUser);
ServerResponse response = userService.resetPasswd(passwordOld,passwordNew,currentUser.getId());
ServerResponse response = userService.resetPasswd(passwordOld, passwordNew, currentUser.getId());
return response;
}
/**
*
*
* 1. `token`
* 2. `token` `redis`
* 3. `User` `userService` `updateInfomation` `ID`
* 4.
*/
@ApiOperation(value="更新当前登陆用户信息", notes="更新用户信息")
@ApiOperation(value = "更新当前登陆用户信息", notes = "更新用户信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "email", value = "邮箱", required = true, dataType = "String"),
@ApiImplicitParam(name = "phone", value = "电话", required = true, dataType = "String"),
@ -204,40 +244,41 @@ public class UserController {
@ApiImplicitParam(name = "answer", value = "答案", required = true, dataType = "String")
})
@RequestMapping("/update_information.do")
public ServerResponse updateInformation(String email,String phone,String question,String answer,HttpServletRequest request){
//1.读取cookie
public ServerResponse updateInformation(String email, String phone, String question, String answer, HttpServletRequest request) {
// 1.读取cookie
String loginToken = CookieUtil.readLoginToken(request);
if(StringUtils.isEmpty(loginToken)){
if (StringUtils.isEmpty(loginToken)) {
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
//2.从redis中获取用户信息
// 2.从redis中获取用户信息
String userStr = commonCacheUtil.getCacheValue(loginToken);
if(userStr == null){
if (userStr == null) {
return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户信息");
}
User currentUser = JsonUtil.Str2Obj(userStr,User.class);
User currentUser = JsonUtil.Str2Obj(userStr, User.class);
ServerResponse response = userService.updateInfomation(email,phone,question,answer,currentUser.getId());
ServerResponse response = userService.updateInfomation(email, phone, question, answer, currentUser.getId());
return response;
}
/**
* ,cookieredis
* `cookie` `redis`
* 1. `token` `cookie`
* 2. 使 `CookieUtil` `delLoginToken` `cookie` 使
* 3. `redis` 使 `commonCacheUtil` `delKey` `redis`
* 4.
*/
@ApiOperation(value="登出", notes="退出登陆删除cookie和redis缓存")
@ApiOperation(value = "登出", notes = "退出登陆删除cookie和redis缓存")
@RequestMapping("/logout.do")
public ServerResponse logout(HttpServletRequest request,HttpServletResponse response){
public ServerResponse logout(HttpServletRequest request, HttpServletResponse response) {
log.info("【用户删除cookie】");
//1.删除cookie
// 1.删除cookie
String loginToken = CookieUtil.readLoginToken(request);
CookieUtil.delLoginToken(request,response);
CookieUtil.delLoginToken(request, response);
log.info("【用户删除redis缓存】");
//2.删除redis中缓存记录
// 2.删除redis中缓存记录
commonCacheUtil.delKey(loginToken);
return ServerResponse.createBySuccess();
}
}

@ -5,34 +5,149 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* `UserMapper` 访DAO
*
* `MyBatis` 使便
* 访
*
* @Author swg.
* @Date 2018/12/31 21:03
* @CONTACT 317758022@qq.com
* @DESC Mapper
*/
@Mapper
// `@Mapper` 注解是 `MyBatis` 框架用于标识该接口为一个映射器接口的注解,
// 告诉 `MyBatis` 框架在启动时扫描并生成该接口的代理实现类,该代理类负责将接口中的方法调用转换为对应的数据库操作(通过执行预定义的 `SQL` 语句,这些语句通常在与接口同名的 `XML` 文件中定义,虽然此处未展示相关 `XML` 文件内容),从而实现与数据库的交互。
public interface UserMapper {
/**
* `id`
* `id` `1` `0`
*
* @param id `Integer`
* @return
*/
int deleteByPrimaryKey(Integer id);
/**
*
* `User` `User`
* `User` `MyBatis`
* `1` `0`
*
* @param record `User`
* @return
*/
int insert(User record);
/**
* `insert` `User` `null`
* `null`
* `1` `0`
*
* @param record `null` `null` `User`
* @return
*/
int insertSelective(User record);
/**
* `id`
* `id` `User` `User`
* `null` `MyBatis` `User`
*
* @param id `Integer`
* @return `User` `null` `User`
*/
User selectByPrimaryKey(Integer id);
/**
* `id` `User` `null`
* `1`
* `0`
*
* @param record `null` `id` `User`
* @return
*/
int updateByPrimaryKeySelective(User record);
/**
* `id` `User`
* `User`
* `1` `0`
*
* @param record `id` `User`
* @return
*/
int updateByPrimaryKey(User record);
/**
* `id`
* `id` `id`
* `null` `MyBatis`
* `id` `id`
*
* @param username `String`
* @return `id` `null`
*/
Integer selectByUsername(String username);
User selectByUsernameAndPasswd(@Param("username") String username,@Param("password") String md5Passwd);
/**
* `MD5`
* `User` `User`
* `null` `MyBatis` `User`
*
*
* @param username `String`
* @param md5Passwd `MD5` `String`
* @return `User` `null` `User`
*/
User selectByUsernameAndPasswd(@Param("username") String username, @Param("password") String md5Passwd);
/**
* `id`
* `id` `id`
* `null` `MyBatis`
* `id`
*
* @param str `String`
* @return `id` `null`
*/
Integer selectByEmail(String str);
/**
*
* `User` `User`
* `null` `MyBatis` `User`
* 使
*
* @param username `String`
* @return `User` `null` `User`
*/
User getUserByUsername(String username);
/**
*
* `User` `User`
* `null` `MyBatis` `User`
* 便
*
* @param username `String`
* @param question `String`
* @param answer `String`
* @return `User` `null` `User`
*/
User getUserByUsernameQuestionAnswer(String username, String question, String answer);
/**
* `id`使
* 使 `1`
* 使 `0`
*
* @param email 使 `String`
* @param userId `id` `null` `id`
* `id` `id` `Integer` `@Param` `userId` `required = false`
* @return `1` `0`
*/
Integer checkEmailValid(@Param("email") String email,@Param("userId") Integer userId);
}

@ -9,35 +9,54 @@ import java.io.Serializable;
import java.util.Date;
/**
* `User`
* 访
* 使 `Lombok` `Getter` `Setter` `toString`
*
* @Author swg.
* @Date 2018/12/31 21:01
* @CONTACT 317758022@qq.com
* @DESC
*/
// `@Data` 注解是 `Lombok` 提供的一个便捷注解,它会自动为类中的所有非静态、非 `final` 的字段生成 `Getter`、`Setter` 方法,
// 以及 `equals`、`hashCode` 和 `toString` 方法(不过这里因为又单独使用了 `@ToString` 注解,所以 `toString` 方法会按照 `@ToString` 注解的配置来生成),方便对类中属性的访问和操作,减少了大量重复的代码编写工作。
@Data
// `@NoArgsConstructor` 注解由 `Lombok` 提供,它会为该类生成一个无参的构造函数,这在一些情况下(比如使用某些框架进行对象实例化时要求类必须有默认的无参构造函数)是很有用的,使得创建 `User` 类的实例更加方便灵活。
@NoArgsConstructor
// `@AllArgsConstructor` 注解同样来自 `Lombok`,它会为类生成一个包含所有字段的全参构造函数,这样在初始化 `User` 类对象时,可以通过传入所有属性的值一次性完成对象的创建,便于在需要完整初始化对象的场景中使用。
@AllArgsConstructor
// `@ToString` 注解用于生成一个方便查看对象信息的 `toString` 方法,默认情况下它会输出类名以及所有字段的名称和对应的值,便于在调试代码、打印对象信息等场景中直观地了解对象的状态。
@ToString
// 实现 `Serializable` 接口表示该类的对象可以被序列化,意味着可以将 `User` 类的对象转换为字节流进行存储(比如保存到文件中或者在网络传输过程中进行传递等),
// 并且在需要的时候能够从字节流中反序列化还原出原来的对象,这在很多涉及数据持久化和分布式系统的场景中是非常必要的操作。
public class User implements Serializable {
// 用户的唯一标识符,通常对应数据库表中的主键字段,用于在系统中唯一确定一个用户,其数据类型为 `Integer`,可以存储整数形式的用户 `ID` 值。
private Integer id;
// 用户名,用于用户登录以及在系统中标识用户的身份,是一个字符串类型的属性,存储用户在注册时设定的用户名信息。
private String username;
// 用户密码,存储用户登录时需要输入验证的密码信息,以加密后的字符串形式存储(在实际应用中应该采用安全的加密算法进行加密处理,比如 `MD5` 等常见加密方式),保证用户密码的安全性,数据类型为 `String`。
private String password;
// 用户的电子邮箱地址,可用于接收系统发送的通知邮件、找回密码等功能相关的邮件信息,是一个字符串类型的属性,存储符合邮箱格式规范的邮箱地址。
private String email;
// 用户的电话号码,可用于联系用户或者作为一些验证操作(如手机验证码登录等功能,如果有相关拓展功能的话)的依据,数据类型为 `String`,存储用户的手机号码等电话号码信息。
private String phone;
// 安全问题,通常用于用户忘记密码时,通过回答预先设置的安全问题来验证身份,进而进行密码重置等操作,是一个字符串类型的属性,存储用户自己设置的安全问题内容。
private String question;
// 安全问题的答案,与 `question` 属性相对应,用于在忘记密码验证身份环节,用户输入答案与数据库中存储的答案进行比对验证,数据类型为 `String`,存储用户针对所设置安全问题的答案内容。
private String answer;
//角色0-管理员,1-普通用户
// 用户角色字段,用于区分不同权限的用户,这里定义了两种角色,`0` 表示管理员,拥有系统的高级管理权限(如用户管理、系统配置等权限),`1` 表示普通用户,只具有普通的使用系统功能的权限,数据类型为 `Integer`。
private Integer role;
// 用户创建时间,记录用户账号在系统中被创建的具体时间点,数据类型为 `Date`,可以准确记录创建时间的日期和时间信息,方便后续进行数据分析、用户行为统计等操作。
private Date createTime;
// 用户信息更新时间,每当用户的相关信息(如密码、邮箱、电话号码等)发生修改时,会更新这个字段的值,记录最后一次更新的时间点,数据类型为 `Date`,同样便于跟踪用户信息的变更情况以及进行相关的数据统计和分析。
private Date updateTime;
}

@ -5,35 +5,123 @@ import com.njupt.swg.entity.User;
import com.njupt.swg.vo.UserResVO;
/**
* `IUserService`
*
* 访
* 便
*
* @Author swg.
* @Date 2018/12/31 21:07
* @CONTACT 317758022@qq.com
* @DESC
*/
public interface IUserService {
/** 用户登陆 **/
ServerResponse<UserResVO> login(String username,String password);
/** 用户注册 **/
/**
*
* 访 `UserMapper`
*
* `ServerResponse<UserResVO>` `ServerResponse`
* `UserResVO` `UserResVO`
*
* @param username `String`
* @param password `String` `MD5`
* @return `ServerResponse<UserResVO>`
*/
ServerResponse<UserResVO> login(String username, String password);
/**
*
* `User` `User`
* 访使
* `ServerResponse`
*
* @param user `User` `User`
* @return `ServerResponse`
*/
ServerResponse register(User user);
/** 判断用户名和邮箱是否重复 **/
/**
*
* `type` `str` 访
* `ServerResponse`
*
* @param str `type` `String`
* @param type `str` `str` "username" "email" `String`
* @return `ServerResponse`
*/
ServerResponse checkValid(String str, String type);
/** 根据用户名去获取设置的忘记密码的问题 **/
/**
*
* 访
* `ServerResponse`
*
* @param username `String`
* @return `ServerResponse`
*/
ServerResponse getQuestionByUsername(String username);
/** 校验问题对应的答案是否正确 **/
/**
*
* 访
* `ServerResponse`
*
* @param username `String`
* @param question `String`
* @param answer `String`
* @return `ServerResponse`
*/
ServerResponse checkAnswer(String username, String question, String answer);
/** 重置密码 **/
/**
*
* `forgetToken`
* 访 `forgetToken`
* `ServerResponse`
*
* @param username `String`
* @param passwordNew `String`
* @param forgetToken `String`
* @return `ServerResponse`
*/
ServerResponse forgetResetPasswd(String username, String passwordNew, String forgetToken);
/** 登陆状态下重置密码 **/
/**
*
* `ID` 访 `ID`
*
* `ServerResponse`
*
* @param passwordOld 使 `String`
* @param passwordNew `String`
* @param userId `int`
* @return `ServerResponse`
*/
ServerResponse resetPasswd(String passwordOld, String passwordNew, int userId);
/** 登陆状态下更新个人信息(更新策略为:如果用户某一项不填,表示保持原样不变) **/
/**
*
* `ID` 访
*
* `ServerResponse`
*
* @param email `String`
* @param phone `String`
* @param question `String`
* @param answer `String`
* @param userId `Integer`
* @return `ServerResponse`
*/
ServerResponse updateInfomation(String email, String phone, String question, String answer, Integer userId);
/**
* `ID` `ID`
* 访 `ID` `UserResVO` `UserResVO` 使
* `null` `UserResVO`
*
* @param userId `Integer`
* @return `UserResVO` `null` `UserResVO`
*/
UserResVO getUserInfoFromDB(Integer userId);
}

@ -8,6 +8,7 @@ import com.njupt.swg.common.utils.MD5Util;
import com.njupt.swg.dao.UserMapper;
import com.njupt.swg.entity.User;
import com.njupt.swg.vo.UserResVO;
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;

Loading…
Cancel
Save