Compare commits

..

No commits in common. 'main' and 'master' have entirely different histories.
main ... master

@ -1,2 +0,0 @@
# software_teamwork

@ -2,7 +2,6 @@
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile default="true" name="Default" enabled="true" />
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="0@192.168.59.129" uuid="ad808a5f-004d-4f31-9402-19010c1be1ab">
<driver-ref>redis</driver-ref>
<data-source source="LOCAL" name="luojia_channel@192.168.59.129" uuid="fef17b9b-50ef-45a3-bed5-7aa6704a7372">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<imported>true</imported>
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
<jdbc-url>jdbc:redis://192.168.59.129:6379/0</jdbc-url>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://192.168.59.129:3306/luojia_channel?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;serverTimezone=Asia/Shanghai</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
@ -14,13 +14,12 @@
</jdbc-additional-properties>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
<data-source source="LOCAL" name="luojia_channel@192.168.59.129" uuid="666814a4-5179-4ab7-96f4-c2a810ed102b">
<driver-ref>mysql.8</driver-ref>
<data-source source="LOCAL" name="0@192.168.59.129" uuid="ad808a5f-004d-4f31-9402-19010c1be1ab">
<driver-ref>redis</driver-ref>
<synchronize>true</synchronize>
<imported>true</imported>
<remarks>$PROJECT_DIR$/service/src/main/resources/application.yaml</remarks>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://192.168.59.129:3306/luojia_channel?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;serverTimezone=Asia/Shanghai</jdbc-url>
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
<jdbc-url>jdbc:redis://192.168.59.129:6379/0</jdbc-url>
<jdbc-additional-properties>
<property name="com.intellij.clouds.kubernetes.db.host.port" />
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />

@ -1,11 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />

@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SqlDialectMappings">
<file url="file://$PROJECT_DIR$/service/src/main/resources/db/luojia_channel.sql" dialect="MySQL" />
<file url="file://$PROJECT_DIR$/service/src/main/resources/db/luojia_channel.sql" dialect="GenericSQL" />
<file url="PROJECT" dialect="MySQL" />
</component>
</project>

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -0,0 +1,7 @@
package com.luojia_channel.common.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisConfig {
}

@ -15,15 +15,7 @@ public class WebMvcConfig implements WebMvcConfigurer {
// 拦截器
registry.addInterceptor(authInterceptor)
.excludePathPatterns("/user/login",
"/user/register",
"/user/captcha",
"/user/verify-captcha",
"/post/list",
"/post/detail",
"/comment/list",
"/comment/list/reply",
"/openapi/luojia-channel",
"/swagger-ui.html"
"/user/register"
);
}

@ -5,6 +5,4 @@ public class RedisConstant {
public static final String REFRESH_TOKEN_PREFIX = "refresh_token:";
// redis存储的黑名单前缀
public static final String BLACKLIST_PREFIX = "blacklist:";
// 重建缓存分布式锁前缀
public static final String SAFE_GET_LOCK_KEY_PREFIX = "safe_get_lock_key_prefix:";
}

@ -1,19 +1,12 @@
package com.luojia_channel.common.domain;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
// 统一返回前端的结果
@Data
@Schema(description = "统一返回前端的结果")
public class Result<T> {
@Schema(description = "状态码")
private int code;
@Schema(description = "提示消息")
private String msg;
@Schema(description = "响应数据")
private T data;
public Result(int code, String msg, T data) {
this.code = code;

@ -12,7 +12,6 @@ import lombok.NoArgsConstructor;
public class UserDTO {
private Long userId;
private String username;
private String avatar;
private String accessToken;
private String refreshToken;
}

@ -30,7 +30,6 @@ public final class JWTUtil {
private static final long NEED_REFRESH_TTL = 60 * 60 * 24 * 7 * 1000; //7天
private static final String USER_ID_KEY = "userId";
private static final String USER_NAME_KEY = "username";
private static final String USER_AVATAR_KEY = "avatar";
public static final String TOKEN_PREFIX = "Bearer ";
public static final String ISS = "luojiachannel";
public static final String SECRET = "SecretKey5464Created2435By54377Forely02345239354893543157956476525685754352976546564766315468763584576";
@ -46,7 +45,6 @@ public final class JWTUtil {
Map<String, Object> customerUserMap = new HashMap<>();
customerUserMap.put(USER_ID_KEY, userInfo.getUserId());
customerUserMap.put(USER_NAME_KEY, userInfo.getUsername());
customerUserMap.put(USER_AVATAR_KEY, userInfo.getAvatar());
String jwtToken = Jwts.builder()
.signWith(SignatureAlgorithm.HS512, SECRET)
.setIssuedAt(new Date())
@ -66,7 +64,6 @@ public final class JWTUtil {
Map<String, Object> customerUserMap = new HashMap<>();
customerUserMap.put(USER_ID_KEY, userInfo.getUserId());
customerUserMap.put(USER_NAME_KEY, userInfo.getUsername());
customerUserMap.put(USER_AVATAR_KEY, userInfo.getAvatar());
String jwtToken = Jwts.builder()
.signWith(SignatureAlgorithm.HS512, SECRET)
.setIssuedAt(new Date())

@ -1,44 +1,26 @@
package com.luojia_channel.common.utils;
import com.luojia_channel.common.domain.page.PageRequest;
import com.luojia_channel.common.domain.page.PageResponse;
import com.luojia_channel.common.domain.page.ScrollPageRequest;
import com.luojia_channel.common.domain.page.ScrollPageResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static com.luojia_channel.common.constants.RedisConstant.SAFE_GET_LOCK_KEY_PREFIX;
@Component
@RequiredArgsConstructor
public class RedisUtil {
private final RedisTemplate<String, Object> redisTemplate;
private final RedissonClient redissonClient;
private static final Long DEFAULT_TIMEOUT = 30000L;
private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
// 获取redisTemplate,因为复杂的redis操作不便于封装
public RedisTemplate<String, Object> getInstance(){
return redisTemplate;
}
/**
* redis
*/
@ -48,73 +30,12 @@ public class RedisUtil {
return value != null ? type.cast(value) : null;
}
// 安全地从缓存中取值
public <T> T safeGet(String key, Class<T> type, Supplier<T> cacheLoader,
long timeout, TimeUnit timeUnit) {
T result = get(key, type);
if(result != null){
return result;
}
// 重建缓存
RLock lock = redissonClient.getLock(SAFE_GET_LOCK_KEY_PREFIX + key);
lock.lock();
try{
if(get(key, type) == null){
T dbResult = cacheLoader.get();
if(dbResult == null){
return null;
}
set(key, dbResult, timeout, timeUnit);
return dbResult;
}
}finally {
lock.unlock();
}
return get(key, type);
}
// 封装基于redis zset的滚动分页查询
public <T> ScrollPageResponse<T> scrollPageQuery(String key, Class<T> type,
ScrollPageRequest pageRequest,
Function<List<Long>, List<T>> dbFallback) {
long max = pageRequest.getLastVal();
long offset = pageRequest.getOffset();
long size = pageRequest.getSize();
Set<ZSetOperations.TypedTuple<Object>> typedTuples = redisTemplate.opsForZSet()
.reverseRangeByScoreWithScores(key, 0, max, offset, size);
if(typedTuples == null || typedTuples.isEmpty()){
return ScrollPageResponse.<T>builder().build();
}
// 获取返回的offset与minTime
List<Long> ids = new ArrayList<>();
int returnOffset = 1;
long min = 0;
for (ZSetOperations.TypedTuple<Object> tuple : typedTuples) {
Long id = (Long)tuple.getValue();
ids.add(id);
long lastVal = tuple.getScore().longValue();
if(lastVal == min){
returnOffset++;
}else{
returnOffset = 1;
min = lastVal;
}
}
List<T> dbList = dbFallback.apply(ids);
return ScrollPageResponse.<T>builder()
.records(dbList)
.size(pageRequest.getSize())
.offset(returnOffset)
.lastVal(min)
.build();
}
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
}
public void set(String key, Object value, long timeout, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
public void expire(String key, long time, TimeUnit timeUnit) {
@ -244,27 +165,4 @@ public class RedisUtil {
}
public <T> List<ZSetItem<T>> zRevRangeWithScores(String key, long count) {
return zRevRangeWithScores(key, 0, count - 1);
}
public <T> List<ZSetItem<T>> zRevRangeWithScores(String key, long start, long end) {
Set<ZSetOperations.TypedTuple<Object>> tuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
return convertTuples(tuples);
}
public <T> T zRevMaxValue(String key) {
List<ZSetItem<T>> items = zRevRangeWithScores(key, 1);
return items.isEmpty() ? null : items.get(0).getValue();
}
public <T> ZSetItem<T> zRevMaxItem(String key) {
List<ZSetItem<T>> items = zRevRangeWithScores(key, 1);
return items.isEmpty() ? null : items.get(0);
}
}

@ -2,7 +2,6 @@ package com.luojia_channel.common.utils;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.luojia_channel.common.domain.UserDTO;
import com.luojia_channel.common.exception.UserException;
import java.util.Optional;
@ -19,15 +18,12 @@ public final class UserContext {
return Optional.ofNullable(userInfoDTO).map(UserDTO::getUserId).orElse(null);
}
public static String getUsername() {
UserDTO userInfoDTO = USER_THREAD_LOCAL.get();
return Optional.ofNullable(userInfoDTO).map(UserDTO::getUsername).orElse(null);
}
public static String getAvatar() {
UserDTO userInfoDTO = USER_THREAD_LOCAL.get();
return Optional.ofNullable(userInfoDTO).map(UserDTO::getAvatar).orElse(null);
}
public static String getAccessToken() {
UserDTO userInfoDTO = USER_THREAD_LOCAL.get();

@ -0,0 +1,3 @@
artifactId=common
groupId=com.luojia
version=1.0.0

@ -0,0 +1,11 @@
com\luojia\luojia_channel\advice\GlobalExceptionHandler.class
com\luojia\luojia_channel\domain\UserDTO.class
com\luojia\luojia_channel\utils\UserContext.class
com\luojia\luojia_channel\utils\JWTUtil.class
com\luojia\luojia_channel\config\RedisConfig.class
com\luojia\luojia_channel\utils\RedisUtil$ZSetItem.class
com\luojia\luojia_channel\domain\UserDTO$UserDTOBuilder.class
com\luojia\luojia_channel\exception\BaseException.class
com\luojia\luojia_channel\utils\RedisUtil.class
com\luojia\luojia_channel\domain\Result.class
com\luojia\luojia_channel\exception\UserException.class

@ -0,0 +1,9 @@
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\advice\GlobalExceptionHandler.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\config\RedisConfig.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\domain\Result.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\domain\UserDTO.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\exception\BaseException.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\exception\UserException.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\utils\JWTUtil.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\utils\RedisUtil.java
D:\javaCode\luojia_channel\common\src\main\java\com\luojia\luojia_channel\utils\UserContext.java

@ -82,12 +82,6 @@
<version>1.2.83</version>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
@ -99,33 +93,8 @@
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.5.12</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>8.4.5</version> <!-- 使用最新版本 -->
</dependency>
<!-- openAPI -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.8</version>
</dependency>
<!-- es -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<build>

@ -20,6 +20,12 @@
<version>1.0.0</version>
</dependency>
<!-- MyBatis-Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
@ -43,7 +49,6 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
@ -55,7 +60,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

@ -0,0 +1,32 @@
package com.luojia_channel.modules.user.controller;
import com.luojia_channel.common.domain.Result;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.service.UserInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/user/info")
@RequiredArgsConstructor
public class UserInfoController {
private final UserInfoService userInfoService;
@PostMapping("/update")
public Result<Void> updateInfo(@RequestBody UserChangeInfoDTO userChangeInfoDTO){
userInfoService.updateInfo(userChangeInfoDTO);
return Result.success();
}
@PostMapping("/password")
public Result<Void> updatePassword(@RequestParam String password){
userInfoService.updatePassword(password);
return Result.success();
}
@PostMapping("/avatar")
public Result<Void> updateAvatar(@RequestParam MultipartFile file){
// TODO 通过oss存储服务或者minio实现头像更新
return Result.success();
}
}

@ -0,0 +1,38 @@
package com.luojia_channel.modules.user.controller;
import com.luojia_channel.common.domain.Result;
import com.luojia_channel.common.domain.UserDTO;
import com.luojia_channel.modules.user.dto.UserLoginDTO;
import com.luojia_channel.modules.user.dto.UserRegisterDTO;
import com.luojia_channel.modules.user.service.UserLoginService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserLoginController {
private final UserLoginService userLoginService;
@PostMapping("/login")
public Result<UserDTO> login(@RequestBody UserLoginDTO userLoginDTO){
return Result.success(userLoginService.login(userLoginDTO));
}
@PostMapping("/register")
public Result<UserDTO> register(@RequestBody UserRegisterDTO userRegisterDTO){
return Result.success(userLoginService.register(userRegisterDTO));
}
@PostMapping("/logout")
public Result<Void> logout(HttpServletRequest request){
userLoginService.logout(request);
return Result.success();
}
@PostMapping("/hello")
public Result<String> hello(){
return Result.success("hello");
}
}

@ -0,0 +1,20 @@
package com.luojia_channel.modules.user.dto;
import lombok.Data;
@Data
public class UserChangeInfoDTO {
private String username;
private String phone;
private String email;
private String studentId;
private String avatar;
private Integer gender;
private String college;
}

@ -0,0 +1,11 @@
package com.luojia_channel.modules.user.dto;
import lombok.Data;
@Data
public class UserLoginDTO {
// 用户标志,支持学号,手机号,邮箱
private String userFlag;
private String password;
}

@ -0,0 +1,16 @@
package com.luojia_channel.modules.user.dto;
import lombok.Data;
@Data
public class UserRegisterDTO {
private String username;
private String password;
private String phone;
private String email;
private String studentId;
}

@ -14,17 +14,34 @@ public class User implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
*
*/
private String username;
/**
*
*/
private String realName;
/**
*
*/
private String password;
/**
*
*/
private String phone;
/**
*
*/
private String email;
/**
*
*/
private String studentId;
/**
@ -37,6 +54,9 @@ public class User implements Serializable {
*/
private Integer gender;
/**
*
*/
private LocalDateTime createTime;
private LocalDateTime updateTime;

@ -4,10 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.luojia_channel.modules.user.entity.User;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper extends BaseMapper<User> {
List<User> selectByIdsOrderByField(List<Long> ids);
}

@ -1,16 +1,11 @@
package com.luojia_channel.modules.user.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.luojia_channel.modules.file.dto.UploadFileDTO;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.entity.User;
import org.springframework.web.multipart.MultipartFile;
public interface UserInfoService extends IService<User> {
void updateInfo(UserChangeInfoDTO userChangeInfoDTO);
void updatePassword(String password);
String uploadAvatar(MultipartFile file);
}

@ -5,18 +5,14 @@ import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luojia_channel.common.exception.UserException;
import com.luojia_channel.common.utils.UserContext;
import com.luojia_channel.modules.file.dto.UploadFileDTO;
import com.luojia_channel.modules.file.service.impl.FileServiceImpl;
import com.luojia_channel.modules.file.utils.GeneratePathUtil;
import com.luojia_channel.modules.file.utils.ValidateFileUtil;
import com.luojia_channel.modules.user.dto.UserChangeInfoDTO;
import com.luojia_channel.modules.user.entity.User;
import com.luojia_channel.modules.user.mapper.UserMapper;
import com.luojia_channel.modules.user.service.UserInfoService;
import com.luojia_channel.modules.user.utils.ValidateUserUtil;
import com.luojia_channel.modules.user.utils.ValidateParameterUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
@ -25,8 +21,7 @@ import java.time.LocalDateTime;
public class UserInfoServiceImpl extends ServiceImpl<UserMapper, User> implements UserInfoService {
private final UserMapper userMapper;
private final ValidateUserUtil validateUserUtil;
private final FileServiceImpl fileService;
private final ValidateParameterUtil validateParameterUtil;
@Override
public void updateInfo(UserChangeInfoDTO userChangeInfoDTO) {
@ -35,7 +30,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserMapper, User> implement
if(currentUser == null){
throw new UserException("用户不存在");
}
validateUserUtil.validateFormats(userChangeInfoDTO, userId);
validateParameterUtil.validateFormats(userChangeInfoDTO, userId);
User user = BeanUtil.copyProperties(userChangeInfoDTO, User.class);
user.setId(userId);
user.setUpdateTime(LocalDateTime.now());
@ -49,7 +44,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserMapper, User> implement
if(user == null){
throw new UserException("用户不存在");
}
if (!password.matches(ValidateUserUtil.PASSWORD_REGEX)) {
if (!password.matches(ValidateParameterUtil.PASSWORD_REGEX)) {
throw new UserException("密码格式不符合要求");
}
if (BCrypt.checkpw(password, user.getPassword())) {
@ -60,9 +55,4 @@ public class UserInfoServiceImpl extends ServiceImpl<UserMapper, User> implement
user.setUpdateTime(LocalDateTime.now());
updateById(user);
}
@Override
public String uploadAvatar(MultipartFile file) {
return fileService.uploadFile(file);
}
}

@ -16,7 +16,7 @@ import com.luojia_channel.modules.user.mapper.UserMapper;
import com.luojia_channel.modules.user.service.UserLoginService;
import com.luojia_channel.common.utils.JWTUtil;
import com.luojia_channel.common.utils.RedisUtil;
import com.luojia_channel.modules.user.utils.ValidateUserUtil;
import com.luojia_channel.modules.user.utils.ValidateParameterUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@ -37,7 +37,7 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
private final UserMapper userMapper;
private final RedisUtil redisUtil;
private final JWTUtil jwtUtil;
private final ValidateUserUtil validateUserUtil;
private final ValidateParameterUtil validateParameterUtil;
/**
*
@ -48,17 +48,17 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
if (StrUtil.isBlank(userFlag)) {
throw new UserException("用户标识不能为空");
}
//使用正则表达式判断类型,之前直接判断长度,虽然不合法的数据在数据库中仍然查不到
// 使用正则表达式判断类型,之前直接判断长度,虽然不合法的数据在数据库中仍然查不到
boolean isEmail = userFlag.contains("@");
boolean isPhone = !isEmail && userFlag.matches(ValidateUserUtil.PHONE_REGEX);
boolean isPhone = !isEmail && userFlag.matches(ValidateParameterUtil.PHONE_REGEX);
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
if (isEmail) {
wrapper.eq(User::getEmail, userFlag);
} else if (isPhone) {
wrapper.eq(User::getPhone, userFlag);
} else {
//默认用户名登录
wrapper.eq(User::getUsername, userFlag);
// 默认学号登录
wrapper.eq(User::getStudentId, userFlag);
}
User user = userMapper.selectOne(wrapper);
if (user == null) {
@ -145,7 +145,7 @@ public class UserLoginServiceImpl extends ServiceImpl<UserMapper, User> implemen
@Transactional(rollbackFor = Exception.class)
public UserDTO register(UserRegisterDTO userRegisterDTO) {
// 校验注册参数
validateUserUtil.validateRegisterUser(userRegisterDTO);
validateParameterUtil.validateRegisterUser(userRegisterDTO);
User user = BeanUtil.copyProperties(userRegisterDTO, User.class);
// 加密
String encodedPassword = BCrypt.hashpw(userRegisterDTO.getPassword(), BCrypt.gensalt());

@ -12,16 +12,16 @@ import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class ValidateUserUtil {
public class ValidateParameterUtil {
// 参数校验正则表达式,学号校验不一定正确
public static final String PHONE_REGEX = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$";
public static final String EMAIL_REGEX = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
public static final String STUDENTID_REGEX = "^(?:\\d{12,13}|[A-Z]{2}\\d{8,10})$";
public static final String PASSWORD_REGEX = "^\\w{6,32}$";
public static final String PASSWORD_REGEX = "^\\w{4,32}$";
private final UserMapper userMapper;
/**
*
*
*
* @param userRegisterDTO
*/
@ -30,6 +30,10 @@ public class ValidateUserUtil {
String password = userRegisterDTO.getPassword();
String phone = userRegisterDTO.getPhone();
String email = userRegisterDTO.getEmail();
String studentId = userRegisterDTO.getStudentId();
if (StrUtil.isBlank(username)){
throw new UserException("用户名不能为空");
}
if (StrUtil.isBlank(password)){
throw new UserException("密码不能为空");
}
@ -38,12 +42,12 @@ public class ValidateUserUtil {
int cnt = 0;
if(StrUtil.isNotBlank(phone)) cnt++;
if(StrUtil.isNotBlank(email)) cnt++;
if(StrUtil.isNotBlank(username)) cnt++;
if(StrUtil.isNotBlank(studentId)) cnt++;
if (cnt == 0) {
throw new UserException("必须填写手机号、邮箱或用户名其中一种注册方式");
throw new UserException("必须填写手机号、邮箱或学号其中一种注册方式");
}
if (cnt > 1) {
throw new UserException("只能选择一种注册方式(手机/邮箱/用户名");
throw new UserException("只能选择一种注册方式(手机/邮箱/学号");
}
// 格式校验
validateFormats(userRegisterDTO);
@ -51,11 +55,13 @@ public class ValidateUserUtil {
// 格式校验,未来更改用户信息时可能使用
// TODO 实际上,用户更改信息校验时数据库查询的不是是否存在,而是是否等于要修改的用户
public void validateFormats(UserRegisterDTO userRegisterDTO) {
String username = userRegisterDTO.getUsername();
String password = userRegisterDTO.getPassword();
String phone = userRegisterDTO.getPhone();
String email = userRegisterDTO.getEmail();
String studentId = userRegisterDTO.getStudentId();
// 仅对非空字段做格式校验
if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getUsername, username))) {
@ -64,13 +70,14 @@ public class ValidateUserUtil {
if(!password.matches(PASSWORD_REGEX)){
throw new UserException("密码格式错误");
}
validateUserFlag(phone, email, null);
validateUserFlag(phone, email, studentId, null);
}
public void validateFormats(UserChangeInfoDTO userChangeInfoDTO, Long currentUserId){
String username = userChangeInfoDTO.getUsername();
String phone = userChangeInfoDTO.getPhone();
String email = userChangeInfoDTO.getEmail();
String studentId = userChangeInfoDTO.getStudentId();
// String college = userChangeInfoDTO.getCollege();
if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getUsername, userChangeInfoDTO.getUsername())
@ -78,10 +85,10 @@ public class ValidateUserUtil {
throw new UserException("用户名已被使用");
}
validateUserFlag(phone, email, currentUserId);
validateUserFlag(phone, email, studentId, currentUserId);
}
private void validateUserFlag(String phone, String email, Long currentUserId) {
private void validateUserFlag(String phone, String email, String studentId, Long currentUserId) {
if(StrUtil.isNotBlank(phone)){
if(!phone.matches(PHONE_REGEX))
throw new UserException("手机号格式错误");
@ -100,6 +107,15 @@ public class ValidateUserUtil {
throw new UserException("邮箱已存在");
}
}
if(StrUtil.isNotBlank(studentId)){
if(!studentId.matches(STUDENTID_REGEX))
throw new UserException("学号格式错误");
if (userMapper.exists(Wrappers.<User>lambdaQuery()
.eq(User::getStudentId, studentId)
.ne(currentUserId != null, User::getId, currentUserId))) {
throw new UserException("学号已存在");
}
}
}
}

@ -0,0 +1,14 @@
# 本地开发环境
lj:
db:
host: 192.168.59.129
password: Forely123!
redis:
host: 192.168.59.129
port: 6379
password: Forely123!
rabbitmq:
host: 192.168.59.129
port: 5672
username: admin
password: Forely123!

@ -1,15 +1,5 @@
server:
port: 8081
springdoc:
api-docs:
path: /openapi/luojia-channel
swagger-ui:
path: /swagger-ui.html
disable-swagger-default-url: true
tags-sorter: alpha
operations-sorter: alpha
packages-to-scan: com.luojia_channel.modules
paths-to-match: /user/**, /post/**, /comment/**, /message/**, /follow/**, /file/**
spring:
application:
name: service
@ -46,11 +36,6 @@ spring:
concurrency: 5
max-concurrency: 10
prefetch: 1
# minio配置
minio:
endpoint: ${lj.minio.endpoint}
accessKey: ${lj.minio.accessKey}
secretKey: ${lj.minio.secretKey}
mybatis-plus:
configuration:
@ -62,8 +47,5 @@ mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.luojia.luojia_channel.modules.*.entity
management:
health:
elasticsearch:
enabled: false

@ -0,0 +1,23 @@
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`real_name` VARCHAR(50) COMMENT '实名',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`phone` VARCHAR(20) UNIQUE COMMENT '注册手机号',
`email` VARCHAR(100) UNIQUE COMMENT '邮箱',
`student_id` VARCHAR(20) UNIQUE COMMENT '学号',
`avatar` VARCHAR(255) COMMENT '头像URL',
`gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`status` INT DEFAULT 1 COMMENT '状态1正常 2冻结',
`role` INT DEFAULT 1 COMMENT '身份1普通用户 2管理员 3超级管理员',
`integral` INT DEFAULT 0 COMMENT '用户积分',
`college` VARCHAR(100) COMMENT '所属学院',
INDEX `idx_username` (`username`),
UNIQUE INDEX `uk_phone` (`phone`),
UNIQUE INDEX `uk_email` (`email`),
UNIQUE INDEX `uk_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

@ -0,0 +1,6 @@
<?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.luojia_channel.modules.user.mapper.UserMapper">
</mapper>

@ -0,0 +1,14 @@
# 本地开发环境
lj:
db:
host: 192.168.59.129
password: Forely123!
redis:
host: 192.168.59.129
port: 6379
password: Forely123!
rabbitmq:
host: 192.168.59.129
port: 5672
username: admin
password: Forely123!

@ -1,15 +1,5 @@
server:
port: 8081
springdoc:
api-docs:
path: /openapi/luojia-channel
swagger-ui:
path: /swagger-ui.html
disable-swagger-default-url: true
tags-sorter: alpha
operations-sorter: alpha
packages-to-scan: com.luojia_channel.modules
paths-to-match: /user/**, /post/**, /comment/**, /message/**, /follow/**, /file/**
spring:
application:
name: service
@ -46,11 +36,6 @@ spring:
concurrency: 5
max-concurrency: 10
prefetch: 1
# minio配置
minio:
endpoint: ${lj.minio.endpoint}
accessKey: ${lj.minio.accessKey}
secretKey: ${lj.minio.secretKey}
mybatis-plus:
configuration:
@ -62,8 +47,5 @@ mybatis-plus:
mapper-locations: classpath*:mapper/**/*.xml
type-aliases-package: com.luojia.luojia_channel.modules.*.entity
management:
health:
elasticsearch:
enabled: false

@ -0,0 +1,23 @@
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
`username` VARCHAR(50) NOT NULL COMMENT '用户名',
`real_name` VARCHAR(50) COMMENT '实名',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`phone` VARCHAR(20) UNIQUE COMMENT '注册手机号',
`email` VARCHAR(100) UNIQUE COMMENT '邮箱',
`student_id` VARCHAR(20) UNIQUE COMMENT '学号',
`avatar` VARCHAR(255) COMMENT '头像URL',
`gender` TINYINT DEFAULT 0 COMMENT '性别0未知1男2女',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`status` INT DEFAULT 1 COMMENT '状态1正常 2冻结',
`role` INT DEFAULT 1 COMMENT '身份1普通用户 2管理员 3超级管理员',
`integral` INT DEFAULT 0 COMMENT '用户积分',
`college` VARCHAR(100) COMMENT '所属学院',
INDEX `idx_username` (`username`),
UNIQUE INDEX `uk_phone` (`phone`),
UNIQUE INDEX `uk_email` (`email`),
UNIQUE INDEX `uk_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

@ -0,0 +1,6 @@
<?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.luojia_channel.modules.user.mapper.UserMapper">
</mapper>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 MiB

@ -1,3 +0,0 @@
{
"java.compile.nullAnalysis.mode": "automatic"
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save