refactor: 基于 novel 项目 & Spring Cloud 2022 & Spring Cloud Alibaba 2022 重构

This commit is contained in:
xiongxiaoyang
2023-03-30 16:15:56 +08:00
parent d68ce51c82
commit 3d098eea5e
505 changed files with 14127 additions and 24067 deletions

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>novel-user</artifactId>
<groupId>io.github.xxyopen</groupId>
<version>2.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>novel-user-service</artifactId>
<dependencies>
<dependency>
<groupId>io.github.xxyopen</groupId>
<artifactId>novel-book-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.github.xxyopen</groupId>
<artifactId>novel-config</artifactId>
</dependency>
<dependency>
<groupId>io.github.xxyopen</groupId>
<artifactId>novel-user-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,22 @@
package io.github.xxyopen.novel.user;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication(scanBasePackages = {"io.github.xxyopen.novel"})
@MapperScan("io.github.xxyopen.novel.user.dao.mapper")
@EnableCaching
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"io.github.xxyopen.novel.book.feign"})
public class NovelUserApplication {
public static void main(String[] args) {
SpringApplication.run(NovelUserApplication.class, args);
}
}

View File

@ -0,0 +1,90 @@
package io.github.xxyopen.novel.user.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.xxyopen.novel.common.auth.JwtUtils;
import io.github.xxyopen.novel.common.auth.UserHolder;
import io.github.xxyopen.novel.common.constant.ErrorCodeEnum;
import io.github.xxyopen.novel.common.constant.SystemConfigConsts;
import io.github.xxyopen.novel.config.exception.BusinessException;
import io.github.xxyopen.novel.user.dto.UserInfoDto;
import io.github.xxyopen.novel.user.manager.cache.UserInfoCacheManager;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
/**
* 认证授权 拦截器:为了注入其它的 Spring beans需要通过 @Component 注解将该拦截器注册到 Spring 上下文
*
* @author xiongxiaoyang
* @date 2022/5/18
*/
@Component
@RequiredArgsConstructor
public class AuthInterceptor implements HandlerInterceptor {
private final ObjectMapper objectMapper;
private final UserInfoCacheManager userInfoCacheManager;
/**
* handle 执行前调用
*/
@SuppressWarnings("NullableProblems")
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取登录 JWT
String token = request.getHeader(SystemConfigConsts.HTTP_AUTH_HEADER_NAME);
// 开始认证
if (!StringUtils.hasText(token)) {
// token 为空
throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED);
}
Long userId = JwtUtils.parseToken(token, SystemConfigConsts.NOVEL_FRONT_KEY);
if (Objects.isNull(userId)) {
// token 解析失败
throw new BusinessException(ErrorCodeEnum.USER_LOGIN_EXPIRED);
}
UserInfoDto userInfo = userInfoCacheManager.getUser(userId);
if (Objects.isNull(userInfo)) {
// 用户不存在
throw new BusinessException(ErrorCodeEnum.USER_ACCOUNT_NOT_EXIST);
}
// 设置 userId 到当前线程
UserHolder.setUserId(userId);
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* handler 执行后调用,出现异常不调用
*/
@SuppressWarnings("NullableProblems")
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* DispatcherServlet 完全处理完请求后调用,出现异常照常调用
*/
@SuppressWarnings("NullableProblems")
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 清理当前线程保存的用户数据
UserHolder.clear();
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}

View File

@ -0,0 +1,36 @@
package io.github.xxyopen.novel.user.config;
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
import io.github.xxyopen.novel.config.interceptor.TokenParseInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Spring Web Mvc 相关配置不要加 @EnableWebMvc 注解,否则会导致 jackson 的全局配置失效。因为 @EnableWebMvc 注解会导致 WebMvcAutoConfiguration 自动配置失效
*
* @author xiongxiaoyang
* @date 2022/5/18
*/
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 权限认证拦截
registry.addInterceptor(authInterceptor)
// 拦截会员中心相关请求接口
.addPathPatterns(ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/**")
// 放行登录注册相关请求接口
.excludePathPatterns(ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/register",
ApiRouterConsts.API_FRONT_USER_URL_PREFIX + "/login")
.order(2);
}
}

View File

@ -0,0 +1,140 @@
package io.github.xxyopen.novel.user.controller.front;
import io.github.xxyopen.novel.book.dto.req.BookCommentReqDto;
import io.github.xxyopen.novel.common.auth.UserHolder;
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
import io.github.xxyopen.novel.common.constant.SystemConfigConsts;
import io.github.xxyopen.novel.common.resp.RestResp;
import io.github.xxyopen.novel.user.dto.req.UserInfoUptReqDto;
import io.github.xxyopen.novel.user.dto.req.UserLoginReqDto;
import io.github.xxyopen.novel.user.dto.req.UserRegisterReqDto;
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserLoginRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserRegisterRespDto;
import io.github.xxyopen.novel.user.manager.feign.BookFeignManager;
import io.github.xxyopen.novel.user.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* 前台门户-会员模块 API 控制器
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
@Tag(name = "UserController", description = "前台门户-会员模块")
@SecurityRequirement(name = SystemConfigConsts.HTTP_AUTH_HEADER_NAME)
@RestController
@RequestMapping(ApiRouterConsts.API_FRONT_USER_URL_PREFIX)
@RequiredArgsConstructor
public class FrontUserController {
private final UserService userService;
private final BookFeignManager bookFeignManager;
/**
* 用户注册接口
*/
@Operation(summary = "用户注册接口")
@PostMapping("register")
public RestResp<UserRegisterRespDto> register(@Valid @RequestBody UserRegisterReqDto dto) {
return userService.register(dto);
}
/**
* 用户登录接口
*/
@Operation(summary = "用户登录接口")
@PostMapping("login")
public RestResp<UserLoginRespDto> login(@Valid @RequestBody UserLoginReqDto dto) {
return userService.login(dto);
}
/**
* 用户信息查询接口
*/
@Operation(summary = "用户信息查询接口")
@GetMapping
public RestResp<UserInfoRespDto> getUserInfo() {
return userService.getUserInfo(UserHolder.getUserId());
}
/**
* 用户信息修改接口
*/
@Operation(summary = "用户信息修改接口")
@PutMapping
public RestResp<Void> updateUserInfo(@Valid @RequestBody UserInfoUptReqDto dto) {
dto.setUserId(UserHolder.getUserId());
return userService.updateUserInfo(dto);
}
/**
* 用户反馈提交接口
*/
@Operation(summary = "用户反馈提交接口")
@PostMapping("feedback")
public RestResp<Void> submitFeedback(@RequestBody String content) {
return userService.saveFeedback(UserHolder.getUserId(), content);
}
/**
* 用户反馈删除接口
*/
@Operation(summary = "用户反馈删除接口")
@DeleteMapping("feedback/{id}")
public RestResp<Void> deleteFeedback(@Parameter(description = "反馈ID") @PathVariable Long id) {
return userService.deleteFeedback(UserHolder.getUserId(), id);
}
/**
* 发表评论接口
*/
@Operation(summary = "发表评论接口")
@PostMapping("comment")
public RestResp<Void> comment(@Valid @RequestBody BookCommentReqDto dto) {
return bookFeignManager.publishComment(dto);
}
/**
* 修改评论接口
*/
@Operation(summary = "修改评论接口")
@PutMapping("comment/{id}")
public RestResp<Void> updateComment(@Parameter(description = "评论ID") @PathVariable Long id,
String content) {
BookCommentReqDto dto = new BookCommentReqDto();
dto.setUserId(UserHolder.getUserId());
dto.setCommentId(id);
dto.setCommentContent(content);
return bookFeignManager.updateComment(dto);
}
/**
* 删除评论接口
*/
@Operation(summary = "删除评论接口")
@DeleteMapping("comment/{id}")
public RestResp<Void> deleteComment(@Parameter(description = "评论ID") @PathVariable Long id) {
BookCommentReqDto dto = new BookCommentReqDto();
dto.setUserId(UserHolder.getUserId());
dto.setCommentId(id);
return bookFeignManager.deleteComment(dto);
}
/**
* 查询书架状态接口 0-不在书架 1-已在书架
*/
@Operation(summary = "查询书架状态接口")
@GetMapping("bookshelf_status")
public RestResp<Integer> getBookshelfStatus(@Parameter(description = "小说ID") String bookId) {
return userService.getBookshelfStatus(UserHolder.getUserId(), bookId);
}
}

View File

@ -0,0 +1,37 @@
package io.github.xxyopen.novel.user.controller.inner;
import io.github.xxyopen.novel.common.constant.ApiRouterConsts;
import io.github.xxyopen.novel.common.resp.RestResp;
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
import io.github.xxyopen.novel.user.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 用户微服务内部调用接口
*
* @author xiongxiaoyang
* @date 2023/3/29
*/
@Tag(name = "InnerBookController", description = "内部调用-用户模块")
@RestController
@RequestMapping(ApiRouterConsts.API_INNER_USER_URL_PREFIX)
@RequiredArgsConstructor
public class InnerUserController {
private final UserService userService;
/**
* 批量查询用户信息
*/
@Operation(summary = "批量查询用户信息")
@PostMapping("listUserInfoByIds")
RestResp<List<UserInfoRespDto>> listUserInfoByIds(@RequestBody List<Long> userIds) {
return userService.listUserInfoByIds(userIds);
}
}

View File

@ -0,0 +1,114 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户书架
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_bookshelf")
public class UserBookshelf implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 小说ID
*/
private Long bookId;
/**
* 上一次阅读的章节内容表ID
*/
private Long preContentId;
/**
* 创建时间;
*/
private LocalDateTime createTime;
/**
* 更新时间;
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getBookId() {
return bookId;
}
public void setBookId(Long bookId) {
this.bookId = bookId;
}
public Long getPreContentId() {
return preContentId;
}
public void setPreContentId(Long preContentId) {
this.preContentId = preContentId;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserBookshelf{" +
"id=" + id +
", userId=" + userId +
", bookId=" + bookId +
", preContentId=" + preContentId +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,142 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户评论
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_comment")
public class UserComment implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 评论用户ID
*/
private Long userId;
/**
* 评论小说ID
*/
private Long bookId;
/**
* 评价内容
*/
private String commentContent;
/**
* 回复数量
*/
private Integer replyCount;
/**
* 审核状态;0-待审核 1-审核通过 2-审核不通过
*/
private Integer auditStatus;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getBookId() {
return bookId;
}
public void setBookId(Long bookId) {
this.bookId = bookId;
}
public String getCommentContent() {
return commentContent;
}
public void setCommentContent(String commentContent) {
this.commentContent = commentContent;
}
public Integer getReplyCount() {
return replyCount;
}
public void setReplyCount(Integer replyCount) {
this.replyCount = replyCount;
}
public Integer getAuditStatus() {
return auditStatus;
}
public void setAuditStatus(Integer auditStatus) {
this.auditStatus = auditStatus;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserComment{" +
"id=" + id +
", userId=" + userId +
", bookId=" + bookId +
", commentContent=" + commentContent +
", replyCount=" + replyCount +
", auditStatus=" + auditStatus +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,125 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户评论回复
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_comment_reply")
public class UserCommentReply implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 评论ID
*/
private Long commentId;
/**
* 回复用户ID
*/
private Long userId;
/**
* 回复内容
*/
private String replyContent;
/**
* 审核状态;0-待审核 1-审核通过 2-审核不通过
*/
private Integer auditStatus;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getCommentId() {
return commentId;
}
public void setCommentId(Long commentId) {
this.commentId = commentId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getReplyContent() {
return replyContent;
}
public void setReplyContent(String replyContent) {
this.replyContent = replyContent;
}
public Integer getAuditStatus() {
return auditStatus;
}
public void setAuditStatus(Integer auditStatus) {
this.auditStatus = auditStatus;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserCommentReply{" +
"id=" + id +
", commentId=" + commentId +
", userId=" + userId +
", replyContent=" + replyContent +
", auditStatus=" + auditStatus +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,156 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户消费记录
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_consume_log")
public class UserConsumeLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 消费用户ID
*/
private Long userId;
/**
* 消费使用的金额;单位:屋币
*/
private Integer amount;
/**
* 消费商品类型;0-小说VIP章节
*/
private Integer productType;
/**
* 消费的的商品ID;例如章节ID
*/
private Long productId;
/**
* 消费的的商品名;例如:章节名
*/
private String producName;
/**
* 消费的的商品值;例如1
*/
private Integer producValue;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
public Integer getProductType() {
return productType;
}
public void setProductType(Integer productType) {
this.productType = productType;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProducName() {
return producName;
}
public void setProducName(String producName) {
this.producName = producName;
}
public Integer getProducValue() {
return producValue;
}
public void setProducValue(Integer producValue) {
this.producValue = producValue;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserConsumeLog{" +
"id=" + id +
", userId=" + userId +
", amount=" + amount +
", productType=" + productType +
", productId=" + productId +
", producName=" + producName +
", producValue=" + producValue +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,97 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户反馈
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_feedback")
public class UserFeedback implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 反馈用户id
*/
private Long userId;
/**
* 反馈内容
*/
private String content;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserFeedback{" +
"id=" + id +
", userId=" + userId +
", content=" + content +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,181 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户信息
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_info")
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 登录名
*/
private String username;
/**
* 登录密码-加密
*/
private String password;
/**
* 加密盐值
*/
private String salt;
/**
* 昵称
*/
private String nickName;
/**
* 用户头像
*/
private String userPhoto;
/**
* 用户性别;0-男 1-女
*/
private Integer userSex;
/**
* 账户余额
*/
private Long accountBalance;
/**
* 用户状态;0-正常
*/
private Integer status;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getUserPhoto() {
return userPhoto;
}
public void setUserPhoto(String userPhoto) {
this.userPhoto = userPhoto;
}
public Integer getUserSex() {
return userSex;
}
public void setUserSex(Integer userSex) {
this.userSex = userSex;
}
public Long getAccountBalance() {
return accountBalance;
}
public void setAccountBalance(Long accountBalance) {
this.accountBalance = accountBalance;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserInfo{" +
"id=" + id +
", username=" + username +
", password=" + password +
", salt=" + salt +
", nickName=" + nickName +
", userPhoto=" + userPhoto +
", userSex=" + userSex +
", accountBalance=" + accountBalance +
", status=" + status +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,195 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户充值记录
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_pay_log")
public class UserPayLog implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 充值用户ID
*/
private Long userId;
/**
* 充值方式;0-支付宝 1-微信
*/
private Integer payChannel;
/**
* 商户订单号
*/
private String outTradeNo;
/**
* 充值金额;单位:分
*/
private Integer amount;
/**
* 充值商品类型;0-屋币 1-包年VIP
*/
private Integer productType;
/**
* 充值商品ID
*/
private Long productId;
/**
* 充值商品名;示例值:屋币
*/
private String productName;
/**
* 充值商品值;示例值255
*/
private Integer productValue;
/**
* 充值时间
*/
private LocalDateTime payTime;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Integer getPayChannel() {
return payChannel;
}
public void setPayChannel(Integer payChannel) {
this.payChannel = payChannel;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
public Integer getProductType() {
return productType;
}
public void setProductType(Integer productType) {
this.productType = productType;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Integer getProductValue() {
return productValue;
}
public void setProductValue(Integer productValue) {
this.productValue = productValue;
}
public LocalDateTime getPayTime() {
return payTime;
}
public void setPayTime(LocalDateTime payTime) {
this.payTime = payTime;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserPayLog{" +
"id=" + id +
", userId=" + userId +
", payChannel=" + payChannel +
", outTradeNo=" + outTradeNo +
", amount=" + amount +
", productType=" + productType +
", productId=" + productId +
", productName=" + productName +
", productValue=" + productValue +
", payTime=" + payTime +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,114 @@
package io.github.xxyopen.novel.user.dao.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 用户阅读历史
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
@TableName("user_read_history")
public class UserReadHistory implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 小说ID
*/
private Long bookId;
/**
* 上一次阅读的章节内容表ID
*/
private Long preContentId;
/**
* 创建时间;
*/
private LocalDateTime createTime;
/**
* 更新时间;
*/
private LocalDateTime updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getBookId() {
return bookId;
}
public void setBookId(Long bookId) {
this.bookId = bookId;
}
public Long getPreContentId() {
return preContentId;
}
public void setPreContentId(Long preContentId) {
this.preContentId = preContentId;
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "UserReadHistory{" +
"id=" + id +
", userId=" + userId +
", bookId=" + bookId +
", preContentId=" + preContentId +
", createTime=" + createTime +
", updateTime=" + updateTime +
"}";
}
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserBookshelf;
/**
* <p>
* 用户书架 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserBookshelfMapper extends BaseMapper<UserBookshelf> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserComment;
/**
* <p>
* 用户评论 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserCommentMapper extends BaseMapper<UserComment> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserCommentReply;
/**
* <p>
* 用户评论回复 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserCommentReplyMapper extends BaseMapper<UserCommentReply> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserConsumeLog;
/**
* <p>
* 用户消费记录 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserConsumeLogMapper extends BaseMapper<UserConsumeLog> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserFeedback;
/**
* <p>
* 用户反馈 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserFeedbackMapper extends BaseMapper<UserFeedback> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserInfo;
/**
* <p>
* 用户信息 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserPayLog;
/**
* <p>
* 用户充值记录 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserPayLogMapper extends BaseMapper<UserPayLog> {
}

View File

@ -0,0 +1,16 @@
package io.github.xxyopen.novel.user.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.xxyopen.novel.user.dao.entity.UserReadHistory;
/**
* <p>
* 用户阅读历史 Mapper 接口
* </p>
*
* @author xiongxiaoyang
* @date 2022/05/11
*/
public interface UserReadHistoryMapper extends BaseMapper<UserReadHistory> {
}

View File

@ -0,0 +1,41 @@
package io.github.xxyopen.novel.user.manager.cache;
import io.github.xxyopen.novel.common.constant.CacheConsts;
import io.github.xxyopen.novel.user.dao.entity.UserInfo;
import io.github.xxyopen.novel.user.dao.mapper.UserInfoMapper;
import io.github.xxyopen.novel.user.dto.UserInfoDto;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* 用户信息 缓存管理类
*
* @author xiongxiaoyang
* @date 2022/5/12
*/
@Component
@RequiredArgsConstructor
public class UserInfoCacheManager {
private final UserInfoMapper userInfoMapper;
/**
* 查询用户信息,并放入缓存中
*/
@Cacheable(cacheManager = CacheConsts.REDIS_CACHE_MANAGER,
value = CacheConsts.USER_INFO_CACHE_NAME)
public UserInfoDto getUser(Long userId) {
UserInfo userInfo = userInfoMapper.selectById(userId);
if (Objects.isNull(userInfo)) {
return null;
}
return UserInfoDto.builder()
.id(userInfo.getId())
.status(userInfo.getStatus()).build();
}
}

View File

@ -0,0 +1,38 @@
package io.github.xxyopen.novel.user.manager.feign;
import io.github.xxyopen.novel.book.dto.req.BookCommentReqDto;
import io.github.xxyopen.novel.book.feign.BookFeign;
import io.github.xxyopen.novel.common.auth.UserHolder;
import io.github.xxyopen.novel.common.resp.RestResp;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 小说微服务调用 Feign 客户端管理
*
* @author xiongxiaoyang
* @date 2023/3/29
*/
@Component
@AllArgsConstructor
public class BookFeignManager {
private final BookFeign bookFeign;
public RestResp<Void> publishComment(BookCommentReqDto dto) {
dto.setUserId(UserHolder.getUserId());
return bookFeign.publishComment(dto);
}
public RestResp<Void> updateComment(BookCommentReqDto dto) {
dto.setUserId(UserHolder.getUserId());
return bookFeign.updateComment(dto);
}
public RestResp<Void> deleteComment(BookCommentReqDto dto) {
dto.setUserId(UserHolder.getUserId());
return bookFeign.deleteComment(dto);
}
}

View File

@ -0,0 +1,39 @@
package io.github.xxyopen.novel.user.manager.redis;
import io.github.xxyopen.novel.common.constant.CacheConsts;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Objects;
/**
* 验证码 管理类
*
* @author xiongxiaoyang
* @date 2022/5/12
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class VerifyCodeManager {
private final StringRedisTemplate stringRedisTemplate;
/**
* 校验图形验证码
*/
public boolean imgVerifyCodeOk(String sessionId, String verifyCode) {
return Objects.equals(stringRedisTemplate.opsForValue()
.get(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + sessionId), verifyCode);
}
/**
* 从 Redis 中删除验证码
*/
public void removeImgVerifyCode(String sessionId) {
stringRedisTemplate.delete(CacheConsts.IMG_VERIFY_CODE_CACHE_KEY + sessionId);
}
}

View File

@ -0,0 +1,89 @@
package io.github.xxyopen.novel.user.service;
import io.github.xxyopen.novel.book.dto.resp.BookEsRespDto;
import io.github.xxyopen.novel.common.resp.RestResp;
import io.github.xxyopen.novel.user.dto.req.UserInfoUptReqDto;
import io.github.xxyopen.novel.user.dto.req.UserLoginReqDto;
import io.github.xxyopen.novel.user.dto.req.UserRegisterReqDto;
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserLoginRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserRegisterRespDto;
import java.util.List;
/**
* 会员模块 服务类
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
public interface UserService {
/**
* 用户注册
*
* @param dto 注册参数
* @return JWT
*/
RestResp<UserRegisterRespDto> register(UserRegisterReqDto dto);
/**
* 用户登录
*
* @param dto 登录参数
* @return JWT + 昵称
*/
RestResp<UserLoginRespDto> login(UserLoginReqDto dto);
/**
* 用户反馈
*
* @param userId 反馈用户ID
* @param content 反馈内容
* @return void
*/
RestResp<Void> saveFeedback(Long userId, String content);
/**
* 用户信息修改
*
* @param dto 用户信息
* @return void
*/
RestResp<Void> updateUserInfo(UserInfoUptReqDto dto);
/**
* 用户反馈删除
*
* @param userId 用户ID
* @param id 反馈ID
* @return void
*/
RestResp<Void> deleteFeedback(Long userId, Long id);
/**
* 查询书架状态接口
*
* @param userId 用户ID
* @param bookId 小说ID
* @return 0-不在书架 1-已在书架
*/
RestResp<Integer> getBookshelfStatus(Long userId, String bookId);
/**
* 用户信息查询
*
* @param userId 用户ID
* @return 用户信息
*/
RestResp<UserInfoRespDto> getUserInfo(Long userId);
/**
* 批量查询用户信息
*
* @param userIds 用户ID列表
* @return 用户信息列表
*/
RestResp<List<UserInfoRespDto>> listUserInfoByIds(List<Long> userIds);
}

View File

@ -0,0 +1,184 @@
package io.github.xxyopen.novel.user.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.github.xxyopen.novel.common.auth.JwtUtils;
import io.github.xxyopen.novel.common.constant.CommonConsts;
import io.github.xxyopen.novel.common.constant.DatabaseConsts;
import io.github.xxyopen.novel.common.constant.ErrorCodeEnum;
import io.github.xxyopen.novel.common.constant.SystemConfigConsts;
import io.github.xxyopen.novel.common.resp.RestResp;
import io.github.xxyopen.novel.config.exception.BusinessException;
import io.github.xxyopen.novel.user.dao.entity.UserBookshelf;
import io.github.xxyopen.novel.user.dao.entity.UserFeedback;
import io.github.xxyopen.novel.user.dao.entity.UserInfo;
import io.github.xxyopen.novel.user.dao.mapper.UserBookshelfMapper;
import io.github.xxyopen.novel.user.dao.mapper.UserFeedbackMapper;
import io.github.xxyopen.novel.user.dao.mapper.UserInfoMapper;
import io.github.xxyopen.novel.user.dto.req.UserInfoUptReqDto;
import io.github.xxyopen.novel.user.dto.req.UserLoginReqDto;
import io.github.xxyopen.novel.user.dto.req.UserRegisterReqDto;
import io.github.xxyopen.novel.user.dto.resp.UserInfoRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserLoginRespDto;
import io.github.xxyopen.novel.user.dto.resp.UserRegisterRespDto;
import io.github.xxyopen.novel.user.manager.redis.VerifyCodeManager;
import io.github.xxyopen.novel.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 会员模块 服务实现类
*
* @author xiongxiaoyang
* @date 2022/5/17
*/
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserInfoMapper userInfoMapper;
private final VerifyCodeManager verifyCodeManager;
private final UserFeedbackMapper userFeedbackMapper;
private final UserBookshelfMapper userBookshelfMapper;
@Override
public RestResp<UserRegisterRespDto> register(UserRegisterReqDto dto) {
// 校验图形验证码是否正确
if (!verifyCodeManager.imgVerifyCodeOk(dto.getSessionId(), dto.getVelCode())) {
// 图形验证码校验失败
throw new BusinessException(ErrorCodeEnum.USER_VERIFY_CODE_ERROR);
}
// 校验手机号是否已注册
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.UserInfoTable.COLUMN_USERNAME, dto.getUsername())
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
if (userInfoMapper.selectCount(queryWrapper) > 0) {
// 手机号已注册
throw new BusinessException(ErrorCodeEnum.USER_NAME_EXIST);
}
// 注册成功,保存用户信息
UserInfo userInfo = new UserInfo();
userInfo.setPassword(
DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8)));
userInfo.setUsername(dto.getUsername());
userInfo.setNickName(dto.getUsername());
userInfo.setCreateTime(LocalDateTime.now());
userInfo.setUpdateTime(LocalDateTime.now());
userInfo.setSalt("0");
userInfoMapper.insert(userInfo);
// 删除验证码
verifyCodeManager.removeImgVerifyCode(dto.getSessionId());
// 生成JWT 并返回
return RestResp.ok(
UserRegisterRespDto.builder()
.token(JwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY))
.uid(userInfo.getId())
.build()
);
}
@Override
public RestResp<UserLoginRespDto> login(UserLoginReqDto dto) {
// 查询用户信息
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.UserInfoTable.COLUMN_USERNAME, dto.getUsername())
.last(DatabaseConsts.SqlEnum.LIMIT_1.getSql());
UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
if (Objects.isNull(userInfo)) {
// 用户不存在
throw new BusinessException(ErrorCodeEnum.USER_ACCOUNT_NOT_EXIST);
}
// 判断密码是否正确
if (!Objects.equals(userInfo.getPassword()
, DigestUtils.md5DigestAsHex(dto.getPassword().getBytes(StandardCharsets.UTF_8)))) {
// 密码错误
throw new BusinessException(ErrorCodeEnum.USER_PASSWORD_ERROR);
}
// 登录成功生成JWT并返回
return RestResp.ok(UserLoginRespDto.builder()
.token(JwtUtils.generateToken(userInfo.getId(), SystemConfigConsts.NOVEL_FRONT_KEY))
.uid(userInfo.getId())
.nickName(userInfo.getNickName()).build());
}
@Override
public RestResp<Void> saveFeedback(Long userId, String content) {
UserFeedback userFeedback = new UserFeedback();
userFeedback.setUserId(userId);
userFeedback.setContent(content);
userFeedback.setCreateTime(LocalDateTime.now());
userFeedback.setUpdateTime(LocalDateTime.now());
userFeedbackMapper.insert(userFeedback);
return RestResp.ok();
}
@Override
public RestResp<Void> updateUserInfo(UserInfoUptReqDto dto) {
UserInfo userInfo = new UserInfo();
userInfo.setId(dto.getUserId());
userInfo.setNickName(dto.getNickName());
userInfo.setUserPhoto(dto.getUserPhoto());
userInfo.setUserSex(dto.getUserSex());
userInfoMapper.updateById(userInfo);
return RestResp.ok();
}
@Override
public RestResp<Void> deleteFeedback(Long userId, Long id) {
QueryWrapper<UserFeedback> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.CommonColumnEnum.ID.getName(), id)
.eq(DatabaseConsts.UserFeedBackTable.COLUMN_USER_ID, userId);
userFeedbackMapper.delete(queryWrapper);
return RestResp.ok();
}
@Override
public RestResp<Integer> getBookshelfStatus(Long userId, String bookId) {
QueryWrapper<UserBookshelf> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(DatabaseConsts.UserBookshelfTable.COLUMN_USER_ID, userId)
.eq(DatabaseConsts.UserBookshelfTable.COLUMN_BOOK_ID, bookId);
return RestResp.ok(
userBookshelfMapper.selectCount(queryWrapper) > 0
? CommonConsts.YES
: CommonConsts.NO
);
}
@Override
public RestResp<UserInfoRespDto> getUserInfo(Long userId) {
UserInfo userInfo = userInfoMapper.selectById(userId);
return RestResp.ok(UserInfoRespDto.builder()
.nickName(userInfo.getNickName())
.userSex(userInfo.getUserSex())
.userPhoto(userInfo.getUserPhoto())
.build());
}
@Override
public RestResp<List<UserInfoRespDto>> listUserInfoByIds(List<Long> userIds) {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.in(DatabaseConsts.CommonColumnEnum.ID.getName(), userIds);
return RestResp.ok(
userInfoMapper.selectList(queryWrapper).stream().map(v -> UserInfoRespDto.builder()
.id(v.getId())
.username(v.getUsername())
.userPhoto(v.getUserPhoto())
.build()).collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,15 @@
server:
port: 9060
spring:
profiles:
include: common
active: dev
management:
# 端点启用配置
endpoint:
logfile:
# 启用返回日志文件内容的端点
enabled: true
# 外部日志文件路径
external-file: logs/novel-user-service.log

View File

@ -0,0 +1,6 @@
spring:
application:
name: novel-user-service
profiles:
include: common

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
<!-- appender是configuration的子节点是负责写日志的组件。 -->
<!-- ConsoleAppender把日志输出到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!-- 控制台也要使用UTF-8不要使用GBK否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- RollingFileAppender滚动记录文件先将日志记录到指定文件当符合某个条件时将日志记录到其他文件 -->
<!-- 以下的大概意思是1.先按日期存日志日期变了将前一天的日志文件名重命名为XXX%日期%索引新的日志仍然是demo.log -->
<!-- 2.如果日期没有发生变化但是当前日志的文件大小超过1KB时对当前日志进行分割 重命名 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>logs/novel-user-service.log</File>
<!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
<!-- TimeBasedRollingPolicy 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 活动文件的名字会根据fileNamePattern的值每隔一段时间改变一次 -->
<!-- 文件名logs/demo.2017-12-05.0.log -->
<fileNamePattern>logs/debug.%d.%i.log</fileNamePattern>
<!-- 每产生一个日志文件该日志文件的保存期限为30天 -->
<maxHistory>30</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小默认值是10MB测试时可改成1KB看效果 -->
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<!-- pattern节点用来设置日志的输入格式 -->
<pattern>
%d %p (%file:%line\)- %m%n
</pattern>
<!-- 记录日志的编码:此处设置字符集 - -->
<charset>UTF-8</charset>
</encoder>
</appender>
<springProfile name="dev">
<!-- ROOT 日志级别 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.maijinjie.springboot 为根包也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<logger name="io.github.xxyopen" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</logger>
</springProfile>
<springProfile name="prod">
<!-- ROOT 日志级别 -->
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
<!-- com.maijinjie.springboot 为根包也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
<!-- 级别依次为【从高到低】FATAL > ERROR > WARN > INFO > DEBUG > TRACE -->
<logger name="io.github.xxyopen" level="ERROR" additivity="false">
<appender-ref ref="FILE"/>
</logger>
</springProfile>
</configuration>