Compare commits
21 Commits
299c9a57ec
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15eca0d0b5 | ||
|
|
f27be2130c | ||
|
|
9b01ee8889 | ||
|
|
505a7a0944 | ||
|
|
51392bf807 | ||
|
|
eb1f70d431 | ||
|
|
47c357695b | ||
|
|
d8c6c74de4 | ||
|
|
5136a3a78b | ||
|
|
25eeab4940 | ||
|
|
f6d1d719a9 | ||
|
|
5803080352 | ||
|
|
9132feb870 | ||
|
|
46be613f28 | ||
|
|
f53e251d46 | ||
|
|
848b13506c | ||
|
|
effcc3838d | ||
|
|
bd6b240f52 | ||
|
|
ffea3e85ae | ||
|
|
8cc4c1da1d | ||
|
|
2809837422 |
777
README_API.md
777
README_API.md
File diff suppressed because it is too large
Load Diff
8880
logs/web_project.log
8880
logs/web_project.log
File diff suppressed because it is too large
Load Diff
Binary file not shown.
53
pom.xml
53
pom.xml
@@ -18,11 +18,7 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.2.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security 核心依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -81,29 +77,13 @@
|
||||
<version>0.18.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JCache API -->
|
||||
<!-- JWT依赖 -->
|
||||
<dependency>
|
||||
<groupId>javax.cache</groupId>
|
||||
<artifactId>cache-api</artifactId>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EHCache 3作为JCache实现 -->
|
||||
<dependency>
|
||||
<groupId>org.ehcache</groupId>
|
||||
<artifactId>ehcache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax</groupId>
|
||||
<artifactId>javaee-api</artifactId>
|
||||
<version>8.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.17</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
<dependencyManagement>
|
||||
@@ -138,6 +118,7 @@
|
||||
<configuration>
|
||||
<mainClass>com.qf.myafterprojecy.MyAfterProjecyApplication</mainClass>
|
||||
<skip>false</skip>
|
||||
<jvmArguments>-Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8</jvmArguments>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -148,7 +129,27 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- 添加资源编码配置 -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<!-- 确保项目编译和资源处理使用UTF-8编码 -->
|
||||
<sourceDirectory>src/main/java</sourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,14 +1,42 @@
|
||||
package com.qf.myafterprojecy;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 应用主类
|
||||
* 设置系统编码并启动Spring Boot应用
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class MyAfterProjecyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 在应用启动前设置系统编码,确保所有输出都使用UTF-8
|
||||
setSystemEncoding();
|
||||
|
||||
// 启动Spring Boot应用
|
||||
SpringApplication.run(MyAfterProjecyApplication.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置系统编码为UTF-8
|
||||
* 解决控制台输出和日志中的中文乱码问题
|
||||
*/
|
||||
private static void setSystemEncoding() {
|
||||
// 设置系统属性,确保所有输出流都使用UTF-8编码
|
||||
System.setProperty("file.encoding", StandardCharsets.UTF_8.name());
|
||||
System.setProperty("sun.stdout.encoding", StandardCharsets.UTF_8.name());
|
||||
System.setProperty("sun.stderr.encoding", StandardCharsets.UTF_8.name());
|
||||
|
||||
// 设置默认字符编码
|
||||
try {
|
||||
java.nio.charset.Charset.defaultCharset();
|
||||
} catch (Exception e) {
|
||||
// 记录编码设置异常
|
||||
System.err.println("设置默认字符编码时发生异常: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.filter.CharacterEncodingFilter;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 字符编码配置类
|
||||
* 确保所有HTTP请求和响应都使用UTF-8编码,解决中文乱码问题
|
||||
*/
|
||||
@Configuration
|
||||
public class CharacterEncodingConfig {
|
||||
|
||||
/**
|
||||
* 创建字符编码过滤器
|
||||
* 优先级设置为最高,确保在所有其他过滤器之前执行
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean<Filter> characterEncodingFilter() {
|
||||
// 创建字符编码过滤器
|
||||
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
|
||||
|
||||
// 设置请求编码为UTF-8
|
||||
encodingFilter.setEncoding(StandardCharsets.UTF_8.name());
|
||||
|
||||
// 强制请求使用UTF-8编码
|
||||
encodingFilter.setForceRequestEncoding(true);
|
||||
|
||||
// 强制响应使用UTF-8编码
|
||||
encodingFilter.setForceResponseEncoding(true);
|
||||
|
||||
// 创建过滤器注册Bean
|
||||
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(encodingFilter);
|
||||
|
||||
// 设置过滤器顺序为最高优先级
|
||||
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
|
||||
|
||||
// 为所有请求路径注册过滤器
|
||||
registrationBean.addUrlPatterns("/*");
|
||||
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
@@ -12,38 +13,67 @@ import org.springframework.web.filter.CorsFilter;
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
// 从配置文件中读取CORS配置
|
||||
@Value("${cors.allowed-origins}")
|
||||
private String allowedOrigins;
|
||||
|
||||
@Value("${cors.allowed-methods}")
|
||||
private String allowedMethods;
|
||||
|
||||
@Value("${cors.allowed-headers}")
|
||||
private String allowedHeaders;
|
||||
|
||||
@Value("${cors.allow-credentials}")
|
||||
private Boolean allowCredentials;
|
||||
|
||||
@Value("${cors.max-age:3600}")
|
||||
private Long maxAge;
|
||||
|
||||
|
||||
/**
|
||||
* 创建CORS过滤器,配置跨域请求的规则
|
||||
* 从配置文件中读取CORS配置,实现配置的统一管理
|
||||
*/
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
// 创建CORS配置对象
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
|
||||
// 允许的来源,这里允许所有来源,实际生产环境应该限制特定域名
|
||||
config.addAllowedOriginPattern("*");
|
||||
|
||||
|
||||
// 允许的来源,从配置文件读取并分割
|
||||
String[] originsArray = allowedOrigins.split(",");
|
||||
for (String origin : originsArray) {
|
||||
config.addAllowedOrigin(origin.trim());
|
||||
}
|
||||
|
||||
// 允许携带凭证(如Cookie)
|
||||
config.setAllowCredentials(true);
|
||||
|
||||
// 允许的请求方法
|
||||
config.addAllowedMethod("*");
|
||||
|
||||
// 允许的请求头
|
||||
config.addAllowedHeader("*");
|
||||
|
||||
// 暴露的响应头,这些头信息可以被前端JavaScript访问
|
||||
config.addExposedHeader("*");
|
||||
|
||||
// 设置预检请求的有效期(秒)
|
||||
config.setMaxAge(3600L);
|
||||
|
||||
config.setAllowCredentials(allowCredentials);
|
||||
|
||||
// 允许的HTTP方法,从配置文件读取并分割
|
||||
String[] methodsArray = allowedMethods.split(",");
|
||||
for (String method : methodsArray) {
|
||||
config.addAllowedMethod(method.trim());
|
||||
}
|
||||
|
||||
// 允许的请求头,从配置文件读取
|
||||
config.addAllowedHeader(allowedHeaders);
|
||||
|
||||
// 明确暴露的响应头,对于JWT认证很重要
|
||||
config.addExposedHeader("Authorization");
|
||||
config.addExposedHeader("Content-Type");
|
||||
config.addExposedHeader("X-Requested-With");
|
||||
config.addExposedHeader("Accept");
|
||||
config.addExposedHeader("Access-Control-Allow-Origin");
|
||||
config.addExposedHeader("Access-Control-Allow-Credentials");
|
||||
|
||||
// 设置预检请求的有效期(秒),从配置文件读取
|
||||
config.setMaxAge(maxAge);
|
||||
|
||||
// 创建基于URL的CORS配置源
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
|
||||
|
||||
// 为所有路径应用CORS配置
|
||||
source.registerCorsConfiguration("/**", config);
|
||||
|
||||
|
||||
// 返回配置好的CORS过滤器
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import com.qf.myafterprojecy.repository.UsersRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义的UserDetailsService实现
|
||||
* 用于从数据库加载用户信息进行认证
|
||||
*/
|
||||
@Component
|
||||
public class CustomUserDetailsService implements UserDetailsService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CustomUserDetailsService.class);
|
||||
|
||||
@Autowired
|
||||
private UsersRepository usersRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
logger.info("用户登录认证: {}", username);
|
||||
|
||||
// 从数据库中查询用户
|
||||
Users user = usersRepository.findByUsername(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("用户不存在: " + username));
|
||||
|
||||
// 转换用户角色为Spring Security的权限
|
||||
// 根据role字段的值设置不同的角色权限
|
||||
String role = "ROLE_USER"; // 默认角色
|
||||
if (user.getRole() == 1) {
|
||||
role = "ROLE_ADMIN"; // 管理员角色
|
||||
}
|
||||
|
||||
List<SimpleGrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority(role));
|
||||
|
||||
// 返回Spring Security的User对象
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
user.getUsername(),
|
||||
user.getPassword(),
|
||||
authorities
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import com.qf.myafterprojecy.utils.JwtUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JWT认证过滤器,用于验证token并授权用户
|
||||
*/
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Value("${jwt.header:Authorization}")
|
||||
private String tokenHeader;
|
||||
|
||||
@Value("${jwt.token-prefix:Bearer}")
|
||||
private String tokenPrefix;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
try {
|
||||
// 获取token
|
||||
String token = getTokenFromRequest(request);
|
||||
System.out.println(token);
|
||||
if (token != null && validateToken(token)) {
|
||||
// 从token中获取用户名
|
||||
String username = jwtUtils.getUsernameFromToken(token);
|
||||
System.out.println("username: " + username);
|
||||
// 加载用户信息
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
// 创建认证对象
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
|
||||
// 设置认证信息到上下文
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("无法设置用户认证: {}", e);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求头中获取token
|
||||
*/
|
||||
private String getTokenFromRequest(HttpServletRequest request) {
|
||||
String bearerToken = request.getHeader(tokenHeader);
|
||||
if (bearerToken != null && bearerToken.startsWith(tokenPrefix + " ")) {
|
||||
return bearerToken.substring(tokenPrefix.length() + 1);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
*/
|
||||
private boolean validateToken(String token) {
|
||||
try {
|
||||
String username = jwtUtils.getUsernameFromToken(token);
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
return jwtUtils.validateToken(token, userDetails);
|
||||
} catch (Exception e) {
|
||||
logger.error("无效的token: {}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
/**
|
||||
* 密码编码器配置类
|
||||
* 用于配置Spring Security使用的密码加密方式
|
||||
*/
|
||||
@Configuration
|
||||
public class PasswordEncoderConfig {
|
||||
|
||||
/**
|
||||
* 创建BCrypt密码编码器
|
||||
* BCrypt是一种强哈希函数,适合密码存储
|
||||
* @return PasswordEncoder实例
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
// 强度设置为10,这是一个平衡安全性和性能的值
|
||||
// 数值越高,计算成本越大,安全性越好
|
||||
return new BCryptPasswordEncoder(10);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,52 @@
|
||||
package com.qf.myafterprojecy.config;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Spring Security配置类
|
||||
* 用于关闭默认的登录验证功能
|
||||
* 配置权限管理功能
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
// 启用方法级别的安全控制
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
|
||||
public class SecurityConfig {
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
private JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* 配置安全过滤器链,允许所有请求通过
|
||||
* 配置AuthenticationManager Bean
|
||||
* 使用AuthenticationConfiguration来获取认证管理器,这是更现代的方式
|
||||
*/
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置安全过滤器链
|
||||
* @param http HttpSecurity对象,用于配置HTTP安全策略
|
||||
* @return 配置好的SecurityFilterChain对象
|
||||
* @throws Exception 配置过程中可能出现的异常
|
||||
@@ -23,18 +54,81 @@ public class SecurityConfig {
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// 启用CORS支持,确保与CorsConfig中配置的过滤器配合工作
|
||||
.cors().and()
|
||||
// 禁用CSRF保护(对于API服务通常不需要)
|
||||
.csrf().disable()
|
||||
// 允许所有请求通过,不需要认证
|
||||
// 配置URL访问权限
|
||||
.authorizeRequests()
|
||||
.anyRequest().permitAll()
|
||||
// 允许公开访问的路径
|
||||
// 登录和认证相关端点应该全部公开
|
||||
.antMatchers(HttpMethod.POST,"/api/auth/**").permitAll()
|
||||
// 文章浏览量增加接口公开
|
||||
.antMatchers(HttpMethod.POST,"/api/articles/view/**").permitAll()
|
||||
// 所有GET请求公开
|
||||
.antMatchers(HttpMethod.GET,"/api/**").permitAll()
|
||||
// 公开评论新增接口
|
||||
.antMatchers(HttpMethod.POST,"/api/messages").permitAll()
|
||||
// 新增、删除、修改操作需要管理员权限
|
||||
.antMatchers(HttpMethod.POST,"/api/**").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.PUT,"/api/**").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE,"/api/**").hasRole("ADMIN")
|
||||
// 管理员才能访问的路径
|
||||
.antMatchers("/api/admin/**").hasRole("ADMIN")
|
||||
// 其他所有请求都需要认证
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
// 禁用表单登录
|
||||
.formLogin().disable()
|
||||
// 禁用HTTP基本认证
|
||||
.httpBasic().disable()
|
||||
// 禁用会话管理(对于无状态API服务)
|
||||
.sessionManagement().disable();
|
||||
// 配置会话管理,使用无状态会话策略
|
||||
// 这意味着每个请求都需要包含认证信息(如JWT)
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
||||
.and()
|
||||
// 确保OPTIONS请求能够通过,处理预检请求
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint((request, response, authException) -> {
|
||||
// 设置CORS头信息
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH");
|
||||
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||
response.setHeader("Access-Control-Max-Age", "3600");
|
||||
|
||||
// 如果是预检请求,直接返回200
|
||||
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
// 未认证处理
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write("{\"message\": \"未授权访问,请先登录\"}");
|
||||
});
|
||||
|
||||
// 添加JWT认证过滤器
|
||||
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
// 确保Spring Security不会添加额外的CharacterEncodingFilter
|
||||
// 因为我们在CharacterEncodingConfig中已经配置了自定义的过滤器
|
||||
http.addFilterBefore((request, response, chain) -> {
|
||||
// 确保响应使用UTF-8编码
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
chain.doFilter(request, response);
|
||||
}, JwtAuthenticationFilter.class);
|
||||
|
||||
// 配置访问拒绝处理器
|
||||
http.exceptionHandling()
|
||||
.accessDeniedHandler((request, response, accessDeniedException) -> {
|
||||
// 设置CORS头信息
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||
|
||||
// 无权限处理
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
response.setContentType("application/json;charset=UTF-8");
|
||||
response.getWriter().write("{\"message\": \"权限不足,无法访问\"}");
|
||||
});
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Article;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArticleDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArriclePageDto;
|
||||
import com.qf.myafterprojecy.service.IArticleService;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -18,6 +22,7 @@ import java.util.List;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/articles")
|
||||
|
||||
@Validated
|
||||
public class ArticleController {
|
||||
|
||||
@@ -33,7 +38,38 @@ public class ArticleController {
|
||||
public ResponseMessage<Article> getArticle(@PathVariable String id) {
|
||||
return articleService.getArticleById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已发布或未发布的文章列表
|
||||
* @return 返回包含已发布文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/published")
|
||||
public ResponseMessage<List<Article>> getPublishedArticles() {
|
||||
return articleService.getPublishedArticles();
|
||||
}
|
||||
/**
|
||||
* 根据状态获取文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/status/{status}")
|
||||
public ResponseMessage<List<Article>> getArticlesByStatus(@PathVariable Integer status) {
|
||||
return articleService.getArticlesByStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态分页获取文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @param page 页码,从0开始(可选,默认为0)
|
||||
* @param size 每页大小(可选,默认为10,最大为100)
|
||||
* @return 返回包含分页文章列表的ResponseMessage对象
|
||||
*/
|
||||
// api/articles/status/page?status=1&page=1&size=2
|
||||
// get 只能这样不能传递json
|
||||
@GetMapping("/status/page")
|
||||
public ResponseMessage<Page<Article>> getArticlesByStatusWithPagination(ArriclePageDto pageDto) {
|
||||
return articleService.getArticlesByStatusWithPagination(pageDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有文章列表
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
@@ -42,7 +78,45 @@ public class ArticleController {
|
||||
public ResponseMessage<List<Article>> getAllArticles() {
|
||||
return articleService.getAllArticles();
|
||||
}
|
||||
/**
|
||||
* 获取文章数量
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回文章数量
|
||||
*/
|
||||
@GetMapping("/count/{status}")
|
||||
public ResponseMessage<Integer> getArticleCount(@PathVariable Integer status) {
|
||||
return articleService.getArticleCount(status);
|
||||
}
|
||||
/**
|
||||
* 根据标题查询文章列表
|
||||
* @param title 文章标题
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/title/{title}")
|
||||
public ResponseMessage<List<Article>> getArticlesByTitle(@PathVariable String title) {
|
||||
return articleService.getArticlesByTitle(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性ID获取该属性下的所有文章
|
||||
* @param attributeId 属性ID
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/attribute/{attributeId}")
|
||||
public ResponseMessage<List<Article>> getArticlesByAttribute(@PathVariable Integer attributeId) {
|
||||
return articleService.getArticlesByAttribute(attributeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性ID获取最新文章(按创建时间降序)
|
||||
* @param attributeId 属性ID
|
||||
* @return 返回包含最新文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/attribute/{attributeId}/latest")
|
||||
public ResponseMessage<List<Article>> getLatestArticlesByAttribute(@PathVariable Integer attributeId) {
|
||||
return articleService.getLatestArticlesByAttribute(attributeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新文章
|
||||
* 仅限AUTHOR角色用户访问
|
||||
@@ -50,20 +124,28 @@ public class ArticleController {
|
||||
* @return 返回包含新创建文章信息的ResponseMessage对象
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('AUTHOR')")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Article> createArticle(@Valid @RequestBody ArticleDto articleDto) {
|
||||
return articleService.saveArticle(articleDto);
|
||||
}
|
||||
|
||||
/**文章浏览量
|
||||
* 增加文章浏览量
|
||||
* @param id 文章ID
|
||||
* @return 返回包含更新后文章信息的ResponseMessage对象
|
||||
*/
|
||||
@PostMapping("/view/{id}")
|
||||
public ResponseMessage<Article> incrementViewCount(@PathVariable Integer id) {
|
||||
return articleService.incrementViewCount(id);
|
||||
}
|
||||
/**
|
||||
* 更新现有文章
|
||||
* 仅限AUTHOR或ADMIN角色用户访问
|
||||
* 仅限AUTHOR角色用户访问
|
||||
* @param id 要更新的文章ID
|
||||
* @param articleDto 包含更新后文章数据的DTO对象
|
||||
* @return 返回包含更新后文章信息的ResponseMessage对象
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasRole('AUTHOR') or hasRole('ADMIN')")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Article> updateArticle(
|
||||
@PathVariable Integer id,
|
||||
@Valid @RequestBody ArticleDto articleDto) {
|
||||
@@ -77,28 +159,9 @@ public class ArticleController {
|
||||
* @return 返回包含被删除文章信息的ResponseMessage对象
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('AUTHOR') or hasRole('ADMIN')")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Article> deleteArticle(@PathVariable Integer id) {
|
||||
return articleService.deleteArticle(id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据分类ID获取该分类下的所有文章
|
||||
* @param typeid 分类ID
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/category/{categoryId}")
|
||||
public ResponseMessage<List<Article>> getArticlesByCategory(@PathVariable Integer typeid) {
|
||||
return articleService.getArticlesByCategory(typeid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览量最高的文章列表
|
||||
* @return 返回包含热门文章列表的ResponseMessage对象
|
||||
*/
|
||||
@GetMapping("/popular")
|
||||
public ResponseMessage<List<Article>> getMostViewedArticles() {
|
||||
return articleService.getMostViewedArticles();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.utils.JwtUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 认证控制器
|
||||
* 处理用户登录相关请求
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthController.class);
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private JwtUtils jwtUtils;
|
||||
|
||||
/**
|
||||
* 用户登录请求体
|
||||
*/
|
||||
static class LoginRequest {
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
// getters and setters
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录接口
|
||||
* @param loginRequest 登录请求参数
|
||||
* @return 登录结果
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public ResponseMessage<Map<String, Object>> login(@RequestBody LoginRequest loginRequest) {
|
||||
logger.info("用户登录请求: {}", loginRequest.getUsername());
|
||||
|
||||
try {
|
||||
// 创建认证令牌
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
|
||||
|
||||
// 执行认证
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
|
||||
// 将认证信息存入上下文
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
// 获取认证后的用户信息
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
// 生成JWT token
|
||||
String token = jwtUtils.generateToken(userDetails);
|
||||
// 构建返回数据
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("username", userDetails.getUsername());
|
||||
data.put("authorities", userDetails.getAuthorities());
|
||||
data.put("token", token);
|
||||
data.put("tokenPrefix", jwtUtils.getTokenPrefix());
|
||||
|
||||
return ResponseMessage.success(data, "登录成功");
|
||||
|
||||
} catch (AuthenticationException e) {
|
||||
logger.error("登录失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("用户名或密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
* @return 当前用户信息
|
||||
*/
|
||||
@PostMapping("/info")
|
||||
public ResponseMessage<Map<String, Object>> getCurrentUserInfo() {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
return ResponseMessage.error("未登录");
|
||||
}
|
||||
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("username", userDetails.getUsername());
|
||||
data.put("authorities", userDetails.getAuthorities());
|
||||
|
||||
return ResponseMessage.success(data, "获取用户信息成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登出接口
|
||||
* @return 登出结果
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public ResponseMessage<Void> logout() {
|
||||
SecurityContextHolder.clearContext();
|
||||
return ResponseMessage.successEmpty("登出成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Categoryattribute;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto;
|
||||
import com.qf.myafterprojecy.service.ICategoryAttributeService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/category-attributes")
|
||||
@Validated
|
||||
public class CategoryAttributeController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CategoryAttributeController.class);
|
||||
|
||||
@Autowired
|
||||
private ICategoryAttributeService categoryAttributeService;
|
||||
|
||||
/**
|
||||
* 根据ID获取分类属性
|
||||
* @param id 属性ID
|
||||
* @return 属性信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseMessage<Categoryattribute> getAttributeById(@PathVariable Integer id) {
|
||||
log.info("接收根据ID获取分类属性的请求: ID={}", id);
|
||||
return categoryAttributeService.getCategoryAttributeById(id);
|
||||
}
|
||||
@GetMapping
|
||||
public ResponseMessage<List<Categoryattribute>> getAttributeCount() {
|
||||
log.info("接收获取分类属性数量的请求");
|
||||
return categoryAttributeService.getAllCategoryAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类ID获取属性列表
|
||||
* @param categoryId 分类ID
|
||||
* @return 属性列表
|
||||
*/
|
||||
@GetMapping("/category/{categoryId}")
|
||||
public ResponseMessage<List<Categoryattribute>> getAttributesByCategory(@PathVariable Integer categoryId) {
|
||||
log.info("接收根据分类ID获取属性列表的请求: 分类ID={}", categoryId);
|
||||
return categoryAttributeService.getAttributesByCategoryId(categoryId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新的分类属性
|
||||
* @param dto 分类属性数据
|
||||
* @return 创建结果
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Categoryattribute> createAttribute(@Valid @RequestBody CategoryAttributeDto dto) {
|
||||
log.info("接收创建分类属性的请求: 分类ID={}, 属性名称={}",
|
||||
dto.getCategoryid(), dto.getAttributename());
|
||||
return categoryAttributeService.saveCategoryAttribute(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分类属性
|
||||
* @param id 属性ID
|
||||
* @param dto 分类属性数据
|
||||
* @return 更新结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Categoryattribute> updateAttribute(
|
||||
@PathVariable Integer id,
|
||||
@Valid @RequestBody CategoryAttributeDto dto) {
|
||||
log.info("接收更新分类属性的请求: ID={}, 分类ID={}, 属性名称={}",
|
||||
id, dto.getCategoryid(), dto.getAttributename());
|
||||
return categoryAttributeService.updateCategoryAttribute(id, dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分类属性
|
||||
* @param id 属性ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Boolean> deleteAttribute(@PathVariable Integer id) {
|
||||
log.info("接收删除分类属性的请求: ID={}", id);
|
||||
return categoryAttributeService.deleteCategoryAttribute(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查分类下是否存在指定名称的属性
|
||||
* @param categoryId 分类ID
|
||||
* @param attributeName 属性名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
@GetMapping("/check-exists")
|
||||
public ResponseMessage<Boolean> checkAttributeExists(
|
||||
@RequestParam Integer categoryId,
|
||||
@RequestParam String attributeName) {
|
||||
log.info("接收检查分类属性是否存在的请求: 分类ID={}, 属性名称={}", categoryId, attributeName);
|
||||
return categoryAttributeService.existsByCategoryAndName(categoryId, attributeName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Category;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryDto;
|
||||
import com.qf.myafterprojecy.service.ICategoryService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分类控制器类,处理分类相关的HTTP请求
|
||||
* 提供分类的增删改查功能
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/categories")
|
||||
@Validated
|
||||
public class CategoryController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CategoryController.class);
|
||||
|
||||
@Autowired
|
||||
private ICategoryService categoryService;
|
||||
|
||||
/**
|
||||
* 根据ID获取分类信息
|
||||
* @param id 分类ID
|
||||
* @return 返回分类信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseMessage<Category> getCategoryById(@PathVariable Integer id) {
|
||||
log.info("接收根据ID获取分类的请求: {}", id);
|
||||
return categoryService.getCategoryById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有分类列表
|
||||
* @return 返回分类列表
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseMessage<List<Category>> getAllCategories() {
|
||||
log.info("接收获取所有分类列表的请求");
|
||||
return categoryService.getAllCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新分类
|
||||
* @param categoryDto 分类数据传输对象
|
||||
* @return 返回创建结果
|
||||
*/
|
||||
@PostMapping
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Category> createCategory(@Valid @RequestBody CategoryDto categoryDto) {
|
||||
log.info("接收创建分类的请求: {}", categoryDto.getTypename());
|
||||
return categoryService.saveCategory(categoryDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分类信息
|
||||
* @param id 分类ID
|
||||
* @param categoryDto 分类数据传输对象
|
||||
* @return 返回更新结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Category> updateCategory(
|
||||
@PathVariable Integer id,
|
||||
@Valid @RequestBody CategoryDto categoryDto) {
|
||||
log.info("接收更新分类的请求: ID={}, 分类名称={}", id, categoryDto.getTypename());
|
||||
return categoryService.updateCategory(id, categoryDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
* @param id 分类ID
|
||||
* @return 返回删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Boolean> deleteCategory(@PathVariable Integer id) {
|
||||
log.info("接收删除分类的请求: {}", id);
|
||||
return categoryService.deleteCategory(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类名称搜索分类
|
||||
* @param typename 分类名称
|
||||
* @return 返回符合条件的分类列表
|
||||
*/
|
||||
@GetMapping("/search")
|
||||
public ResponseMessage<List<Category>> searchCategoriesByTypename(@RequestParam String typename) {
|
||||
log.info("接收根据名称搜索分类的请求: {}", typename);
|
||||
return categoryService.searchCategoriesByTypename(typename);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
@@ -10,6 +9,8 @@ import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -31,7 +32,7 @@ public class HelpController {
|
||||
public ResponseMessage<String> getReadmeApi() {
|
||||
try {
|
||||
// 获取项目根目录
|
||||
String rootPath = System.getProperty("user.dir");
|
||||
String rootPath = System.getProperty("user.dir") ;
|
||||
// 构建README_API.md文件路径
|
||||
File readmeFile = new File(rootPath, "README_API.md");
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessageDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessagePageDto;
|
||||
import com.qf.myafterprojecy.service.IMessageService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
@@ -28,7 +31,25 @@ public class MessageController {
|
||||
logger.info("接收获取所有消息的请求");
|
||||
return messageService.getAllMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询消息
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public ResponseMessage<List<Message>> getMessagesByPage(MessagePageDto messagePageDto) {
|
||||
logger.info("接收分页查询消息的请求: {}", messagePageDto);
|
||||
return messageService.getMessagesByPage(messagePageDto);
|
||||
}
|
||||
/**
|
||||
* 获取消息数量
|
||||
* @param articleId 文章ID (可选)
|
||||
* @return 消息数量
|
||||
* 文章ID为null时返回所有消息数量
|
||||
*/
|
||||
@GetMapping("/count")
|
||||
public ResponseMessage<Integer> getMessageCount( Integer articleId) {
|
||||
logger.info("接收获取消息数量的请求: {}", articleId);
|
||||
return messageService.getMessageCountByArticleId(articleId);
|
||||
}
|
||||
/**
|
||||
* 根据ID获取消息
|
||||
*/
|
||||
@@ -37,26 +58,6 @@ public class MessageController {
|
||||
logger.info("接收根据ID获取消息的请求: {}", id);
|
||||
return messageService.getMessageById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新消息
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseMessage<Message> createMessage(@RequestBody MessageDto message) {
|
||||
logger.info("接收创建消息的请求: {}", message != null ? message.getNickname() : "null");
|
||||
return messageService.saveMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID删除消息
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseMessage<Message> deleteMessage(@PathVariable Integer id) {
|
||||
logger.info("接收删除消息的请求: {}", id);
|
||||
return messageService.deleteMessage(id);
|
||||
}
|
||||
|
||||
// 新增API端点
|
||||
|
||||
/**
|
||||
* 根据文章ID获取消息列表
|
||||
@@ -95,11 +96,34 @@ public class MessageController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定文章的评论数量
|
||||
* 创建新消息
|
||||
*/
|
||||
@GetMapping("/count/article/{articleId}")
|
||||
public ResponseMessage<Long> getMessageCountByArticleId(@PathVariable Integer articleId) {
|
||||
logger.info("接收获取文章评论数量的请求: {}", articleId);
|
||||
return messageService.getMessageCountByArticleId(articleId);
|
||||
@PostMapping
|
||||
// 允许匿名用户发表评论
|
||||
public ResponseMessage<Message> createMessage(@RequestBody MessageDto message) {
|
||||
logger.info("接收创建消息的请求: {}", message != null ? message.getNickname() : "null");
|
||||
return messageService.saveMessage(message);
|
||||
}
|
||||
// 点赞数增加
|
||||
@PostMapping("/{id}/like")
|
||||
public ResponseMessage<Message> likeMessage(@PathVariable Integer id) {
|
||||
logger.info("接收点赞消息的请求: {}", id);
|
||||
return messageService.likeMessage(id);
|
||||
}
|
||||
/**
|
||||
* 根据ID删除消息
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id")
|
||||
public ResponseMessage<Message> deleteMessage(@PathVariable Integer id) {
|
||||
logger.info("接收删除消息的请求: {}", id);
|
||||
return messageService.deleteMessage(id);
|
||||
}
|
||||
//删除所有评论 - 仅管理员可操作
|
||||
@DeleteMapping("/all")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Void> deleteAllMessages() {
|
||||
logger.info("接收删除所有消息的请求");
|
||||
return messageService.deleteAllMessages();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Nonsense;
|
||||
import com.qf.myafterprojecy.pojo.dto.NonsenseDto;
|
||||
import com.qf.myafterprojecy.service.INonsenseService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/nonsense")
|
||||
@Validated
|
||||
public class NonsenseController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(NonsenseController.class);
|
||||
|
||||
@Autowired
|
||||
private INonsenseService nonsenseService;
|
||||
|
||||
/**
|
||||
* 获取所有疯言疯语内容
|
||||
* @return 疯言疯语内容列表
|
||||
*/
|
||||
@GetMapping
|
||||
public ResponseMessage<List<Nonsense>> getAllNonsense() {
|
||||
logger.info("请求获取所有疯言疯语内容");
|
||||
return nonsenseService.getAllNonsense();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态获取疯言疯语内容
|
||||
* @param status 状态:0未发表 1已发表 2已删除
|
||||
* @return 疯言疯语内容列表
|
||||
*/
|
||||
@GetMapping("/status/{status}")
|
||||
public ResponseMessage<List<Nonsense>> getNonsenseByStatus(
|
||||
@PathVariable("status") Integer status) {
|
||||
logger.info("请求获取状态为{}的疯言疯语内容", status);
|
||||
return nonsenseService.getNonsenseByStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取疯言疯语内容
|
||||
* @param id 疯言疯语内容ID
|
||||
* @return 疯言疯语内容
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseMessage<Nonsense> getNonsenseById(@PathVariable("id") Integer id) {
|
||||
logger.info("请求获取ID为{}的疯言疯语内容", id);
|
||||
return nonsenseService.getNonsenseById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建疯言疯语内容
|
||||
* 需要管理员权限
|
||||
* @param nonsenseDto 疯言疯语内容数据
|
||||
* @return 创建结果
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseMessage<Nonsense> saveNonsense(@Valid @RequestBody NonsenseDto nonsenseDto) {
|
||||
logger.info("请求保存疯言疯语内容");
|
||||
return nonsenseService.saveNonsense(nonsenseDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新疯言疯语内容
|
||||
* 需要管理员权限
|
||||
* @param id 疯言疯语内容ID
|
||||
* @param nonsenseDto 疯言疯语内容数据
|
||||
* @return 更新结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Nonsense> updateNonsense(@PathVariable("id") Integer id, @Valid @RequestBody NonsenseDto nonsenseDto) {
|
||||
logger.info("请求更新ID为{}的疯言疯语内容", id);
|
||||
return nonsenseService.updateNonsense(id, nonsenseDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除疯言疯语内容
|
||||
* 需要管理员权限
|
||||
* @param id 疯言疯语内容ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Boolean> deleteNonsense(@PathVariable("id") Integer id) {
|
||||
logger.info("请求删除ID为{}的疯言疯语内容", id);
|
||||
return nonsenseService.deleteNonsense(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新疯言疯语内容状态
|
||||
* 需要管理员权限
|
||||
* @param id 疯言疯语内容ID
|
||||
* @param status 新状态:0未发表 1已发表 2已删除
|
||||
* @return 更新结果
|
||||
*/
|
||||
@PutMapping("/{id}/status/{status}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Nonsense> updateNonsenseStatus(
|
||||
@PathVariable("id") Integer id,
|
||||
@PathVariable("status") @Min(0) @Max(2) Integer status) {
|
||||
logger.info("请求更新ID为{}的疯言疯语内容状态为{}", id, status);
|
||||
return nonsenseService.updateNonsenseStatus(id, status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.qf.myafterprojecy.controller;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import com.qf.myafterprojecy.pojo.dto.UserDto;
|
||||
import com.qf.myafterprojecy.service.IUserService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
@Validated
|
||||
public class UserController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
|
||||
|
||||
@Autowired
|
||||
private IUserService userService;
|
||||
|
||||
/**
|
||||
* 根据ID获取用户信息
|
||||
* @param id 用户ID
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public ResponseMessage<Users> getUserById(@PathVariable Long id) {
|
||||
logger.info("获取用户信息,用户ID: {}", id);
|
||||
return userService.getUserById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户列表
|
||||
* @return 用户列表
|
||||
*/
|
||||
@GetMapping
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<List<Users>> getAllUsers() {
|
||||
logger.info("获取所有用户列表");
|
||||
return userService.getAllUsers();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名获取用户信息
|
||||
* @return 用户信息
|
||||
*/
|
||||
@GetMapping("/username/{username}")
|
||||
@PreAuthorize("hasRole('ADMIN') or #username == authentication.name")
|
||||
public ResponseMessage<Users> getUserByUsername(@PathVariable String username) {
|
||||
logger.info("根据用户名获取用户信息,用户名: {}", username);
|
||||
return userService.getUserByUsername(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新用户
|
||||
* @param userDto 用户数据
|
||||
* @return 创建结果
|
||||
*/
|
||||
@PostMapping
|
||||
public ResponseMessage<Users> saveUser(@Valid @RequestBody UserDto userDto) {
|
||||
logger.info("创建新用户,用户名: {}", userDto.getUsername());
|
||||
return userService.saveUser(userDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param id 用户ID
|
||||
* @param userDto 用户数据
|
||||
* @return 更新结果
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN') or #id == authentication.principal.id")
|
||||
public ResponseMessage<Users> updateUser(@PathVariable Long id, @Valid @RequestBody UserDto userDto) {
|
||||
logger.info("更新用户信息,用户ID: {}", id);
|
||||
return userService.updateUser(id, userDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<Boolean> deleteUser(@PathVariable Long id) {
|
||||
logger.info("删除用户,用户ID: {}", id);
|
||||
return userService.deleteUser(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色查询用户列表
|
||||
* @param role 角色
|
||||
* @return 用户列表
|
||||
*/
|
||||
@GetMapping("/role/{role}")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseMessage<List<Users>> getUsersByRole(@PathVariable int role) {
|
||||
logger.info("根据角色查询用户列表,角色: {}", role);
|
||||
return userService.getUsersByRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户名是否存在
|
||||
* @param username 用户名
|
||||
* @return 是否存在
|
||||
*/
|
||||
@GetMapping("/check/username/{username}")
|
||||
public ResponseMessage<Boolean> existsByUsername(@PathVariable String username) {
|
||||
logger.info("检查用户名是否存在,用户名: {}", username);
|
||||
return userService.existsByUsername(username);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查邮箱是否存在
|
||||
* @param email 邮箱
|
||||
* @return 是否存在
|
||||
*/
|
||||
@GetMapping("/check/email/{email}")
|
||||
public ResponseMessage<Boolean> existsByEmail(@PathVariable String email) {
|
||||
logger.info("检查邮箱是否存在,邮箱: {}", email);
|
||||
return userService.existsByEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查手机号是否存在
|
||||
* @param phone 手机号
|
||||
* @return 是否存在
|
||||
*/
|
||||
@GetMapping("/check/phone/{phone}")
|
||||
public ResponseMessage<Boolean> existsByPhone(@PathVariable String phone) {
|
||||
logger.info("检查手机号是否存在,手机号: {}", phone);
|
||||
return userService.existsByPhone(phone);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
package com.qf.myafterprojecy;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
|
||||
package com.qf.myafterprojecy.exceptopn;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
package com.qf.myafterprojecy.exceptopn;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* 通用响应消息类,用于封装接口返回的数据结构
|
||||
* 遵循RESTful API设计规范,提供统一的响应格式
|
||||
* @param <T> 数据类型,可以是任意Java对象
|
||||
*/
|
||||
@Data
|
||||
public class ResponseMessage<T> {
|
||||
// 状态码,通常用于表示请求的处理结果
|
||||
private Integer code;
|
||||
// 响应消息,用于描述请求的处理结果信息
|
||||
private String message;
|
||||
// 请求是否成功的标志,根据状态码自动设置
|
||||
private boolean success;
|
||||
// 响应数据,泛型类型,支持不同类型的数据
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 构造方法,用于创建响应消息对象
|
||||
* 自动根据状态码设置success字段
|
||||
* @param code 状态码
|
||||
* @param message 响应消息
|
||||
* @param data 响应数据
|
||||
*/
|
||||
public ResponseMessage(Integer code, String message, T data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
// 自动根据状态码判断是否成功
|
||||
this.success = code >= 200 && code < 300;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完整参数的构造方法
|
||||
* @param code 状态码
|
||||
* @param message 响应消息
|
||||
* @param data 响应数据
|
||||
* @param success 是否成功
|
||||
*/
|
||||
public ResponseMessage(Integer code, String message, T data, boolean success) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
// ----------------------------------- 成功响应方法 -----------------------------------
|
||||
|
||||
/**
|
||||
* 创建成功响应,默认消息为"操作成功"
|
||||
* @param data 响应数据
|
||||
* @param <T> 数据类型
|
||||
* @return 成功响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> success(T data) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), "操作成功", data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成功响应,自定义消息
|
||||
* @param data 响应数据
|
||||
* @param message 响应消息
|
||||
* @param <T> 数据类型
|
||||
* @return 成功响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> success(T data, String message) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), message, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成功响应,自定义状态码
|
||||
* @param code 状态码
|
||||
* @param message 响应消息
|
||||
* @param data 响应数据
|
||||
* @param <T> 数据类型
|
||||
* @return 成功响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> successWithCode(Integer code, String message, T data) {
|
||||
return new ResponseMessage<>(code, message, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建空数据的成功响应
|
||||
* @param message 响应消息
|
||||
* @param <T> 数据类型
|
||||
* @return 成功响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> successEmpty(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), message, null, true);
|
||||
}
|
||||
|
||||
// ----------------------------------- 错误响应方法 -----------------------------------
|
||||
|
||||
/**
|
||||
* 创建错误响应,默认状态码500
|
||||
* @param message 错误消息
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> error(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建错误响应,自定义状态码
|
||||
* @param code 状态码
|
||||
* @param message 错误消息
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> error(Integer code, String message) {
|
||||
return new ResponseMessage<>(code, message, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建错误响应,包含错误数据
|
||||
* @param code 状态码
|
||||
* @param message 错误消息
|
||||
* @param data 错误数据
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> errorWithData(Integer code, String message, T data) {
|
||||
return new ResponseMessage<>(code, message, data, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建参数错误响应,状态码400
|
||||
* @param message 错误消息
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> badRequest(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.BAD_REQUEST.value(), message, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建未找到资源响应,状态码404
|
||||
* @param message 错误消息
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> notFound(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.NOT_FOUND.value(), message, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建权限错误响应,状态码403
|
||||
* @param message 错误消息
|
||||
* @param <T> 数据类型
|
||||
* @return 错误响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> forbidden(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.FORBIDDEN.value(), message, null, false);
|
||||
}
|
||||
|
||||
// ----------------------------------- 业务操作响应方法 -----------------------------------
|
||||
|
||||
/**
|
||||
* 创建保存操作响应
|
||||
* @param success 是否成功
|
||||
* @param data 响应数据
|
||||
* @param <T> 数据类型
|
||||
* @return 操作响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> save(boolean success, T data) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "保存成功", data, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "保存失败", null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建更新操作响应
|
||||
* @param success 是否成功
|
||||
* @param data 响应数据
|
||||
* @param <T> 数据类型
|
||||
* @return 操作响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> update(boolean success, T data) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "更新成功", data, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "更新失败", null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建删除操作响应
|
||||
* @param success 是否成功
|
||||
* @param <T> 数据类型
|
||||
* @return 操作响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> delete(boolean success) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "删除成功", null, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "删除失败", null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建批量删除操作响应
|
||||
* @param success 是否成功
|
||||
* @param deletedCount 删除的数量
|
||||
* @param <T> 数据类型
|
||||
* @return 操作响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> batchDelete(boolean success, int deletedCount) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "成功删除" + deletedCount + "条数据", null, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "批量删除失败", null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建分页查询响应
|
||||
* @param data 分页数据
|
||||
* @param message 响应消息
|
||||
* @param <T> 数据类型
|
||||
* @return 分页响应对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> page(T data, String message) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), message, data, true);
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.qf.myafterprojecy.init;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
import com.qf.myafterprojecy.repository.MessageRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 消息数据初始化类,用于在应用启动时为Message表添加默认的测试数据
|
||||
*/
|
||||
@Component
|
||||
public class MessageDataInit implements ApplicationRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessageDataInit.class);
|
||||
|
||||
@Autowired
|
||||
private MessageRepository messageRepository;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
logger.info("===== 消息数据初始化开始 =====");
|
||||
|
||||
// 检查数据库中是否已有消息数据
|
||||
long count = messageRepository.count();
|
||||
logger.info("当前数据库中消息数量: {}", count);
|
||||
|
||||
// 如果没有消息数据,添加一些测试数据
|
||||
if (count == 0) {
|
||||
logger.info("数据库中没有消息数据,开始添加初始化数据...");
|
||||
addInitialMessages();
|
||||
} else {
|
||||
logger.info("数据库中已存在消息数据,无需初始化");
|
||||
}
|
||||
|
||||
logger.info("===== 消息数据初始化结束 =====");
|
||||
}
|
||||
|
||||
private void addInitialMessages() {
|
||||
// 添加第一篇文章的评论
|
||||
Message message1 = new Message();
|
||||
message1.setNickname("系统用户");
|
||||
message1.setEmail("system@example.com");
|
||||
message1.setContent("这是系统自动添加的第一条评论,欢迎使用本系统!");
|
||||
message1.setCreatedAt(new Date());
|
||||
message1.setArticleid(1);
|
||||
message1.setParentid(null); // 根评论
|
||||
messageRepository.save(message1);
|
||||
|
||||
// 添加回复
|
||||
Message reply1 = new Message();
|
||||
reply1.setNickname("管理员");
|
||||
reply1.setEmail("admin@example.com");
|
||||
reply1.setContent("感谢您的支持,如有任何问题请随时联系我们!");
|
||||
reply1.setCreatedAt(new Date());
|
||||
reply1.setArticleid(1);
|
||||
reply1.setParentid(message1.getMessageid()); // 回复第一条评论
|
||||
messageRepository.save(reply1);
|
||||
|
||||
// 添加第二篇文章的评论
|
||||
Message message2 = new Message();
|
||||
message2.setNickname("访客");
|
||||
message2.setEmail("visitor@example.com");
|
||||
message2.setContent("这篇文章写得非常好,学到了很多知识。");
|
||||
message2.setCreatedAt(new Date());
|
||||
message2.setArticleid(2);
|
||||
message2.setParentid(null);
|
||||
messageRepository.save(message2);
|
||||
|
||||
// 再添加一些测试数据
|
||||
Message message3 = new Message();
|
||||
message3.setNickname("测试用户1");
|
||||
message3.setEmail("test1@example.com");
|
||||
message3.setContent("这是测试内容1");
|
||||
message3.setCreatedAt(new Date());
|
||||
message3.setArticleid(1);
|
||||
message3.setParentid(null);
|
||||
messageRepository.save(message3);
|
||||
|
||||
Message reply2 = new Message();
|
||||
reply2.setNickname("测试用户2");
|
||||
reply2.setEmail("test2@example.com");
|
||||
reply2.setContent("回复测试内容1");
|
||||
reply2.setCreatedAt(new Date());
|
||||
reply2.setArticleid(1);
|
||||
reply2.setParentid(message3.getMessageid());
|
||||
messageRepository.save(reply2);
|
||||
|
||||
logger.info("成功添加了{}条初始化消息数据", messageRepository.count());
|
||||
}
|
||||
}
|
||||
65
src/main/java/com/qf/myafterprojecy/init/UserDataInit.java
Normal file
65
src/main/java/com/qf/myafterprojecy/init/UserDataInit.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.qf.myafterprojecy.init;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import com.qf.myafterprojecy.repository.UsersRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 用户数据初始化类
|
||||
* 在应用启动时检查并创建管理员账号
|
||||
*/
|
||||
@Component
|
||||
public class UserDataInit implements ApplicationRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserDataInit.class);
|
||||
|
||||
@Autowired
|
||||
private UsersRepository usersRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
// 管理员账号信息
|
||||
private static final String ADMIN_USERNAME = "qf1121";
|
||||
private static final String ADMIN_PASSWORD = "qf1121";
|
||||
private static final String ADMIN_EMAIL = "admin@qf1121.com";
|
||||
private static final String ADMIN_PHONE = "13800138000";
|
||||
private static final Integer ADMIN_ROLE = 1; // 1表示管理员角色
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
logger.info("开始检查管理员账号...");
|
||||
|
||||
// 检查管理员账号是否已存在
|
||||
Optional<Users> adminUser = usersRepository.findByUsername(ADMIN_USERNAME);
|
||||
|
||||
if (adminUser.isPresent()) {
|
||||
logger.info("管理员账号 {} 已存在,无需创建", ADMIN_USERNAME);
|
||||
} else {
|
||||
// 创建管理员账号
|
||||
Users newAdmin = new Users();
|
||||
newAdmin.setUsername(ADMIN_USERNAME);
|
||||
// 加密密码
|
||||
newAdmin.setPassword(passwordEncoder.encode(ADMIN_PASSWORD));
|
||||
newAdmin.setEmail(ADMIN_EMAIL);
|
||||
newAdmin.setPhone(ADMIN_PHONE);
|
||||
newAdmin.setRole(ADMIN_ROLE);
|
||||
newAdmin.setCreateTime(LocalDateTime.now());
|
||||
try {
|
||||
usersRepository.save(newAdmin);
|
||||
logger.info("管理员账号 {} 创建成功", ADMIN_USERNAME);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建管理员账号失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,12 @@ public class Article {
|
||||
@Column(name = "title")
|
||||
private String title;
|
||||
|
||||
@NotBlank(message = "内容不能为空")
|
||||
@Column(name = "content", columnDefinition = "TEXT")
|
||||
private String content;
|
||||
|
||||
@NotNull(message = "类别id不能为空")
|
||||
@Column(name = "typeid")
|
||||
private Integer typeid;
|
||||
@Column(name = "attribute_id")
|
||||
private Integer attributeid;
|
||||
|
||||
@Column(name = "img")
|
||||
private String img;
|
||||
@@ -33,14 +32,38 @@ public class Article {
|
||||
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@Column(name = "view_count")
|
||||
private Integer viewCount;
|
||||
|
||||
@Column(name = "likes")
|
||||
private Integer likes; // 点赞数
|
||||
|
||||
@Column(name = "status")
|
||||
private Integer status; // 0-草稿,1-已发布,2-已删除
|
||||
|
||||
@Column(name = "markdownscontent")
|
||||
private String markdownscontent;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
public Integer getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
public void setLikes(Integer likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
|
||||
public Integer getArticleid() {
|
||||
return articleid;
|
||||
@@ -66,14 +89,6 @@ public class Article {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Integer getTypeid() {
|
||||
return typeid;
|
||||
}
|
||||
|
||||
public void setTypeid(Integer typeid) {
|
||||
this.typeid = typeid;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
@@ -113,4 +128,12 @@ public class Article {
|
||||
public void setViewCount(Integer viewCount) {
|
||||
this.viewCount = viewCount;
|
||||
}
|
||||
|
||||
public String getMarkdownscontent() {
|
||||
return markdownscontent;
|
||||
}
|
||||
|
||||
public void setMarkdownscontent(String markdownscontent) {
|
||||
this.markdownscontent = markdownscontent;
|
||||
}
|
||||
}
|
||||
|
||||
68
src/main/java/com/qf/myafterprojecy/pojo/Category.java
Normal file
68
src/main/java/com/qf/myafterprojecy/pojo/Category.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package com.qf.myafterprojecy.pojo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "category")
|
||||
public class Category {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "categoryid")
|
||||
private Integer categoryid;
|
||||
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
@Column(name = "typename")
|
||||
private String typename;
|
||||
|
||||
@Column(name = "description")
|
||||
private String description;
|
||||
|
||||
@Column(name = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at")
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getCategoryid() {
|
||||
return categoryid;
|
||||
}
|
||||
|
||||
public void setCategoryid(Integer categoryid) {
|
||||
this.categoryid = categoryid;
|
||||
}
|
||||
|
||||
public String getTypename() {
|
||||
return typename;
|
||||
}
|
||||
|
||||
public void setTypename(String typename) {
|
||||
this.typename = typename;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.qf.myafterprojecy.pojo;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "category_attribute")
|
||||
public class Categoryattribute {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "attributeid")
|
||||
private Integer attributeid;
|
||||
|
||||
@Column(name = "categoryid")
|
||||
private Integer categoryid;
|
||||
|
||||
@Column(name = "attributename")
|
||||
private String attributename;
|
||||
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
|
||||
public Integer getCategoryid() {
|
||||
return categoryid;
|
||||
}
|
||||
|
||||
public void setCategoryid(Integer categoryid) {
|
||||
this.categoryid = categoryid;
|
||||
}
|
||||
|
||||
public String getAttributename() {
|
||||
return attributename;
|
||||
}
|
||||
|
||||
public void setAttributename(String attributename) {
|
||||
this.attributename = attributename;
|
||||
}
|
||||
}
|
||||
@@ -8,22 +8,53 @@ import java.util.Date;
|
||||
public class Message {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "messageid")
|
||||
private Integer messageid;
|
||||
|
||||
@Column(name = "nickname")
|
||||
private String nickname;
|
||||
|
||||
@Column(name = "email")
|
||||
private String email;
|
||||
|
||||
@Column(columnDefinition = "text")
|
||||
@Column(name = "content", columnDefinition = "text")
|
||||
private String content;
|
||||
|
||||
@Column(name = "messageimg")
|
||||
private String messageimg;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "created_at")
|
||||
private Date createdAt;
|
||||
|
||||
@Column(name = "parentid")
|
||||
private Integer parentid;
|
||||
|
||||
private Integer articleid;
|
||||
@Column(name = "replyid")
|
||||
private Integer replyid;
|
||||
|
||||
@Column(name = "articleid")
|
||||
private Integer articleid;
|
||||
|
||||
@Column(name = "likes")
|
||||
private Integer likes; // 点赞数
|
||||
|
||||
|
||||
public Integer getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
public void setLikes(Integer likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
|
||||
public Integer getReplyid() {
|
||||
return replyid;
|
||||
}
|
||||
|
||||
public void setReplyid(Integer replyid) {
|
||||
this.replyid = replyid;
|
||||
}
|
||||
|
||||
public Integer getMessageid() {
|
||||
return messageid;
|
||||
@@ -80,4 +111,12 @@ public class Message {
|
||||
public void setArticleid(Integer articleid) {
|
||||
this.articleid = articleid;
|
||||
}
|
||||
|
||||
public String getMessageimg() {
|
||||
return messageimg;
|
||||
}
|
||||
|
||||
public void setMessageimg(String messageimg) {
|
||||
this.messageimg = messageimg;
|
||||
}
|
||||
}
|
||||
|
||||
46
src/main/java/com/qf/myafterprojecy/pojo/Nonsense.java
Normal file
46
src/main/java/com/qf/myafterprojecy/pojo/Nonsense.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.qf.myafterprojecy.pojo;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
|
||||
@Entity
|
||||
@Table(name = "nonsense")
|
||||
public class Nonsense {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false, unique = true)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "content",nullable = false)
|
||||
private String content;
|
||||
|
||||
@Column(name = "status",nullable = false)
|
||||
private Integer status;//状态 0:未发表 1:已发表 2:已删除
|
||||
|
||||
@Column(name = "time")
|
||||
private Date time;
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
package com.qf.myafterprojecy.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.http.HttpStatus;
|
||||
/**
|
||||
* 通用响应消息类,用于封装接口返回的数据结构
|
||||
* 使用泛型T来支持不同类型的数据返回
|
||||
* @param <T> 数据类型,可以是任意Java对象
|
||||
*/
|
||||
@Data
|
||||
public class ResponseMessage<T> {
|
||||
// 状态码,通常用于表示请求的处理结果
|
||||
private Integer code;
|
||||
// 响应消息,用于描述请求的处理结果信息
|
||||
private String message;
|
||||
// 请求是否成功的标志
|
||||
private boolean success;
|
||||
// 响应数据,泛型类型,支持不同类型的数据
|
||||
private T data;
|
||||
/**
|
||||
* 构造方法,用于创建响应消息对象
|
||||
* @param code 状态码
|
||||
* @param message 响应消息
|
||||
* @param data 响应数据
|
||||
*/
|
||||
public ResponseMessage(Integer code, String message, T data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// 获取成功状态的getter方法
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
// 设置成功状态的setter方法
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
// 获取状态码的getter方法
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
// 设置状态码的setter方法
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
// 获取响应消息的getter方法
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
// 设置响应消息的setter方法
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
// 获取响应数据的getter方法
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
// 设置响应数据的setter方法
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
/**
|
||||
* 完整参数的构造方法
|
||||
* @param code 状态码
|
||||
* @param message 响应消息
|
||||
* @param data 响应数据
|
||||
* @param success 是否成功
|
||||
*/
|
||||
public ResponseMessage(Integer code, String message, T data, boolean success) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
// 接口请求成功
|
||||
public static <T> ResponseMessage<T> success(T data ,String message ,boolean success) {
|
||||
return new ResponseMessage(HttpStatus.OK.value(), message, data ,success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个表示操作失败的响应消息
|
||||
* @param message 失败原因的描述信息
|
||||
* @return 返回一个包含错误状态码和错误信息的ResponseMessage对象
|
||||
*/
|
||||
public static <T> ResponseMessage<T> failure(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null, false);
|
||||
}
|
||||
|
||||
|
||||
public static <T> ResponseMessage<T> success(T data) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), "操作成功", data, true);
|
||||
}
|
||||
|
||||
public static <T> ResponseMessage<T> success(T data, String message) {
|
||||
return new ResponseMessage<>(HttpStatus.OK.value(), message, data, true);
|
||||
}
|
||||
|
||||
public static <T> ResponseMessage<T> error(String message) {
|
||||
return new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), message, null, false);
|
||||
}
|
||||
|
||||
public static <T> ResponseMessage<T> error(Integer code, String message) {
|
||||
return new ResponseMessage<>(code, message, null, false);
|
||||
}
|
||||
|
||||
public static <T> ResponseMessage<T> Save(boolean success) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "保存成功", null, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "保存失败", null, false);
|
||||
}
|
||||
|
||||
public static <T> ResponseMessage<T> Delete(boolean success) {
|
||||
return success ?
|
||||
new ResponseMessage<>(HttpStatus.OK.value(), "删除成功", null, true) :
|
||||
new ResponseMessage<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "删除失败", null, false);
|
||||
}
|
||||
|
||||
}
|
||||
89
src/main/java/com/qf/myafterprojecy/pojo/Users.java
Normal file
89
src/main/java/com/qf/myafterprojecy/pojo/Users.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package com.qf.myafterprojecy.pojo;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Entity
|
||||
@Table(name = "users")
|
||||
public class Users {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", nullable = false, unique = true)
|
||||
private Long id;
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Column(name = "username", nullable = false, unique = true)
|
||||
private String username;
|
||||
@NotBlank(message = "密码不能为空")
|
||||
@Column(name = "password", nullable = false)
|
||||
private String password;
|
||||
@NotBlank(message = "邮箱不能为空")
|
||||
@Column(name = "email", nullable = false, unique = true)
|
||||
private String email;
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
@Column(name = "phone", nullable = false, unique = true)
|
||||
private String phone;
|
||||
@Column(name = "role", nullable = false)
|
||||
private int role;
|
||||
@Column(name = "create_time", nullable = false)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
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 getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public int getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(int role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
public class ArriclePageDto {
|
||||
|
||||
private Integer status;
|
||||
private String title;
|
||||
private Integer attributeid;
|
||||
private Integer categoryid;
|
||||
private Integer pagenum;
|
||||
private Integer pagesize;
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
public Integer getPagenum() {
|
||||
return pagenum;
|
||||
}
|
||||
public void setPagenum(Integer pagenum) {
|
||||
this.pagenum = pagenum;
|
||||
}
|
||||
public Integer getPagesize() {
|
||||
return pagesize;
|
||||
}
|
||||
public void setPagesize(Integer pagesize) {
|
||||
this.pagesize = pagesize;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
public Integer getCategoryid() {
|
||||
return categoryid;
|
||||
}
|
||||
public void setCategoryid(Integer categoryid) {
|
||||
this.categoryid = categoryid;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArPageDto{" +
|
||||
"status=" + status +
|
||||
", pagenum=" + pagenum +
|
||||
", pagesize=" + pagesize +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,36 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Getter
|
||||
public class ArticleDto {
|
||||
private Integer id;
|
||||
private Integer articleid;
|
||||
|
||||
@NotBlank(message = "标题不能为空")
|
||||
private String title;
|
||||
|
||||
@NotBlank(message = "内容不能为空")
|
||||
private String content;
|
||||
private String content;// 如果为空说明是长篇文章 不为空则是短篇说说
|
||||
|
||||
@NotNull(message = "属性ID不能为空")
|
||||
private Integer attributeid;
|
||||
|
||||
private String img;
|
||||
|
||||
private Integer viewCount;
|
||||
|
||||
private Integer likes;
|
||||
|
||||
private Integer status;
|
||||
|
||||
// Getters and Setters
|
||||
private String markdownscontent; // 文章内容的Markdown格式
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
// Getters and Setters
|
||||
public Integer getArticleid() {
|
||||
return articleid;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
public void setArticleid(Integer articleid) {
|
||||
this.articleid = articleid;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
@@ -45,12 +49,12 @@ public class ArticleDto {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
|
||||
public String getImg() {
|
||||
@@ -60,4 +64,36 @@ public class ArticleDto {
|
||||
public void setImg(String img) {
|
||||
this.img = img;
|
||||
}
|
||||
|
||||
public Integer getViewCount() {
|
||||
return viewCount;
|
||||
}
|
||||
|
||||
public void setViewCount(Integer viewCount) {
|
||||
this.viewCount = viewCount;
|
||||
}
|
||||
|
||||
public Integer getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
public void setLikes(Integer likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMarkdownscontent() {
|
||||
return markdownscontent;
|
||||
}
|
||||
|
||||
public void setMarkdownscontent(String markdownscontent) {
|
||||
this.markdownscontent = markdownscontent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public class CategoryAttributeDto {
|
||||
private Integer attributeid;
|
||||
|
||||
@NotNull(message = "分类ID不能为空")
|
||||
private Integer categoryid;
|
||||
|
||||
@NotBlank(message = "属性名称不能为空")
|
||||
private String attributename;
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
|
||||
public Integer getCategoryid() {
|
||||
return categoryid;
|
||||
}
|
||||
|
||||
public void setCategoryid(Integer categoryid) {
|
||||
this.categoryid = categoryid;
|
||||
}
|
||||
|
||||
public String getAttributename() {
|
||||
return attributename;
|
||||
}
|
||||
|
||||
public void setAttributename(String attributename) {
|
||||
this.attributename = attributename;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CategoryDto {
|
||||
private Integer Categoryid;
|
||||
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
private String typename;
|
||||
|
||||
private String description;
|
||||
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getCategoryid() {
|
||||
return Categoryid;
|
||||
}
|
||||
|
||||
public void setCategoryid(Integer Categoryid) {
|
||||
this.Categoryid = Categoryid;
|
||||
}
|
||||
|
||||
public String getTypename() {
|
||||
return typename;
|
||||
}
|
||||
|
||||
public void setTypename(String typename) {
|
||||
this.typename = typename;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(LocalDateTime createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getUpdatedAt() {
|
||||
return updatedAt;
|
||||
}
|
||||
|
||||
public void setUpdatedAt(LocalDateTime updatedAt) {
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
|
||||
public class MessageDto {
|
||||
@@ -15,10 +14,23 @@ public class MessageDto {
|
||||
private Date createdAt;
|
||||
|
||||
private Integer parentid;
|
||||
|
||||
private Integer replyid;
|
||||
|
||||
private Integer articleid;
|
||||
|
||||
private Integer likes;
|
||||
|
||||
private String messageimg;
|
||||
|
||||
public Integer getReplyid() {
|
||||
return replyid;
|
||||
}
|
||||
|
||||
public void setReplyid(Integer replyid) {
|
||||
this.replyid = replyid;
|
||||
}
|
||||
|
||||
public Integer getMessageid() {
|
||||
return messageid;
|
||||
}
|
||||
@@ -74,4 +86,20 @@ public class MessageDto {
|
||||
public void setArticleid(Integer articleid) {
|
||||
this.articleid = articleid;
|
||||
}
|
||||
|
||||
public Integer getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
public void setLikes(Integer likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
|
||||
public String getMessageimg() {
|
||||
return messageimg;
|
||||
}
|
||||
|
||||
public void setMessageimg(String messageimg) {
|
||||
this.messageimg = messageimg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
public class MessagePageDto {
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
private Integer articleid;
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
public Integer getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
public void setPageSize(Integer pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
public Integer getArticleid() {
|
||||
return articleid;
|
||||
}
|
||||
public void setArticleid(Integer articleid) {
|
||||
this.articleid = articleid;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MessagePageDto{" +
|
||||
"pageNum=" + pageNum +
|
||||
", pageSize=" + pageSize +
|
||||
", articleid=" + articleid +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class NonsenseDto {
|
||||
private Integer id;
|
||||
|
||||
private String content;
|
||||
|
||||
private Integer status;//状态 0:未发表 1:已发表 2:已删除
|
||||
|
||||
private Date time;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
69
src/main/java/com/qf/myafterprojecy/pojo/dto/UserDto.java
Normal file
69
src/main/java/com/qf/myafterprojecy/pojo/dto/UserDto.java
Normal file
@@ -0,0 +1,69 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class UserDto {
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "密码不能为空")
|
||||
private String password;
|
||||
|
||||
@NotBlank(message = "邮箱不能为空")
|
||||
private String email;
|
||||
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
private String phone;
|
||||
|
||||
private int role;
|
||||
|
||||
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 getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public int getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(int role) {
|
||||
this.role = role;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Article;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@@ -10,53 +12,124 @@ import org.springframework.stereotype.Repository;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository // 表明这是一个数据访问层组件,用于持久层操作
|
||||
@Repository // 表明这是一个数据访问层组件,用于持久层操作
|
||||
public interface ArticleRepository extends JpaRepository<Article, Integer> {
|
||||
/**
|
||||
* 根据文章ID查询文章信息的方法
|
||||
* 使用JPQL(Java Persistence Query Language)进行查询
|
||||
*
|
||||
* @param id 文章的唯一标识符,作为查询条件
|
||||
* @return 返回一个Optional<Article>对象,可能包含文章信息,也可能为空(如果未找到对应ID的文章)
|
||||
*/
|
||||
/**
|
||||
* 根据文章ID查询文章信息的方法
|
||||
* 使用JPQL(Java Persistence Query Language)进行查询
|
||||
*
|
||||
* @param id 文章的唯一标识符,作为查询条件
|
||||
* @return 返回一个Optional<Article>对象,可能包含文章信息,也可能为空(如果未找到对应ID的文章)
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.articleid = :id")
|
||||
Optional<Article> findById(@Param("id") Integer id);
|
||||
/**
|
||||
* 根据文章ID查询已发布的文章
|
||||
* 使用JPQL查询语句,只查询状态为1(已发布)且指定ID的文章
|
||||
*
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
|
||||
/**
|
||||
* 根据标题查询文章列表
|
||||
*
|
||||
* @param title 文章标题的一部分,用于模糊查询
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.title LIKE %:title%")
|
||||
List<Article> findByTitle(@Param("title") String title);
|
||||
|
||||
/**
|
||||
* 根据文章ID查询已发布的文章
|
||||
* 使用JPQL查询语句,只查询状态为1(已发布)且指定ID的文章
|
||||
*
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = 1")
|
||||
List<Article> findPublishedByAuthor();
|
||||
|
||||
/**
|
||||
* 根据分类ID查询已发布的文章列表
|
||||
* 使用JPQL查询语句,筛选状态为已发布(status=1)且指定分类(typeid)的文章
|
||||
*
|
||||
* @param typeid 分类ID,通过@Param注解映射到查询语句中的:typeid参数
|
||||
* @return 返回符合条件Article对象的列表
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = 1 AND a.typeid = :typeid")
|
||||
List<Article> findPublishedByCategory(@Param("typeid") Integer typeid);
|
||||
/**
|
||||
* 根据分类ID查询已发布的文章列表
|
||||
* 使用JPQL查询语句,筛选状态为已发布(status=1)且指定分类(typeid)的文章
|
||||
*
|
||||
* @param attributeid 分类ID,通过@Param注解映射到查询语句中的:attributeid参数
|
||||
* @return 返回符合条件Article对象的列表
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid")
|
||||
List<Article> findPublishedByAttribute(@Param("attributeid") Integer attributeid);
|
||||
|
||||
/**
|
||||
* 使用@Modifying注解标记这是一个修改操作,通常用于UPDATE或DELETE语句
|
||||
* 使用@Query注解定义自定义的JPQL查询语句
|
||||
* 该查询用于将指定文章的浏览量(viewCount)增加1
|
||||
*
|
||||
* @param articleid 文章的唯一标识符,通过@Param注解将方法参数与查询参数绑定
|
||||
*/
|
||||
/**
|
||||
* 根据属性ID查询最新的文章列表
|
||||
* 使用JPQL查询语句,筛选状态为已发布(status=1)且指定属性(attributeid)的文章,按创建时间降序排序
|
||||
*
|
||||
* @param attributeid 属性ID,通过@Param注解映射到查询语句中的:attributeid参数
|
||||
* @return 返回符合条件Article对象的列表,按创建时间降序排列
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = 1 AND a.attributeid = :attributeid ORDER BY a.createdAt DESC")
|
||||
List<Article> findLatestByAttribute(@Param("attributeid") Integer attributeid);
|
||||
|
||||
/**
|
||||
* 使用@Modifying注解标记这是一个修改操作,通常用于UPDATE或DELETE语句
|
||||
* 使用@Query注解定义自定义的JPQL查询语句
|
||||
* 该查询用于将指定文章的浏览量(viewCount)增加1
|
||||
*
|
||||
* @param articleid 文章的唯一标识符,通过@Param注解将方法参数与查询参数绑定
|
||||
*/
|
||||
@Modifying
|
||||
@Query("UPDATE Article a SET a.viewCount = a.viewCount + 1 WHERE a.articleid = :articleid")
|
||||
@Query("UPDATE Article a SET a.viewCount = COALESCE(a.viewCount, 0) + 1 WHERE a.articleid = :articleid")
|
||||
void incrementViewCount(@Param("articleid") Integer articleid);
|
||||
|
||||
/**
|
||||
* 根据浏览量降序查询状态为1的所有文章
|
||||
* 该查询使用JPQL语句,从Article实体中选取数据
|
||||
*
|
||||
* @return 返回一个Article对象的列表,按浏览量(viewCount)降序排列
|
||||
*/
|
||||
/**
|
||||
* 根据浏览量降序查询状态为1的所有文章
|
||||
* 该查询使用JPQL语句,从Article实体中选取数据
|
||||
*
|
||||
* @return 返回一个Article对象的列表,按浏览量(viewCount)降序排列
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = 1 ORDER BY a.viewCount DESC")
|
||||
List<Article> findMostViewed();
|
||||
|
||||
/**
|
||||
* 根据状态查询文章列表
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @return 返回符合状态条件的文章列表
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = :status")
|
||||
List<Article> findByStatus(@Param("status") Integer status);
|
||||
|
||||
/**
|
||||
* 根据状态分页查询文章列表
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @param pageable 分页参数,包含页码、每页大小和排序信息
|
||||
* @return 返回符合状态条件的文章分页结果
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = :status ORDER BY a.createdAt DESC")
|
||||
Page<Article> findByStatusWithPagination(@Param("status") Integer status, Pageable pageable);
|
||||
/**
|
||||
* 根据属性ID数组分页查询文章列表
|
||||
* @param attributeids 文章属性ID数组
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @param pageable 分页参数,包含页码、每页大小和排序信息
|
||||
* @return 返回符合状态条件的文章分页结果
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = :status AND a.attributeid IN :attributeids ORDER BY a.createdAt DESC")
|
||||
Page<Article> findByStatusWithPagination(@Param("status") Integer status, @Param("attributeids") List<Integer> attributeids, Pageable pageable);
|
||||
/**
|
||||
* 根据属性ID分页查询文章列表
|
||||
* @param attributeid 文章属性ID
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @param pageable 分页参数,包含页码、每页大小和排序信息
|
||||
* @return 返回符合状态条件的文章分页结果
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = :status AND a.attributeid = :attributeid ORDER BY a.createdAt DESC")
|
||||
Page<Article> findByStatusWithPagination(@Param("status") Integer status, @Param("attributeid") Integer attributeid, Pageable pageable);
|
||||
/**
|
||||
* 根据文章标题分页模糊查询文章列表
|
||||
* @param title 文章标题
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @param pageable 分页参数,包含页码、每页大小和排序信息
|
||||
* @return 返回符合状态条件的文章分页结果
|
||||
*/
|
||||
@Query("SELECT a FROM Article a WHERE a.status = :status AND a.title LIKE %:title% ORDER BY a.createdAt DESC")
|
||||
Page<Article> findByStatusWithPagination(@Param("status") Integer status, @Param("title") String title, Pageable pageable);
|
||||
/**
|
||||
* 统计指定状态的文章数量
|
||||
* @param status 文章状态,0-草稿,1-已发布,2-已删除
|
||||
* @return 返回符合状态条件的文章数量
|
||||
*/
|
||||
@Query("SELECT COUNT(a) FROM Article a WHERE a.status = :status")
|
||||
Integer countByStatus(@Param("status") Integer status);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Categoryattribute;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CategoryAttributeRepository extends JpaRepository<Categoryattribute, Integer> {
|
||||
|
||||
/**
|
||||
* 根据分类ID查询分类属性列表
|
||||
* @param categoryid 分类ID
|
||||
* @return 返回该分类下的所有属性列表
|
||||
*/
|
||||
@Query("SELECT ca FROM Categoryattribute ca WHERE ca.categoryid = :categoryid")
|
||||
List<Categoryattribute> findByCategoryId(@Param("categoryid") Integer categoryid);
|
||||
|
||||
/**
|
||||
* 根据属性ID查询属性信息
|
||||
* @param attributeid 属性ID
|
||||
* @return 返回属性对象
|
||||
*/
|
||||
@Query("SELECT ca FROM Categoryattribute ca WHERE ca.attributeid = :attributeid")
|
||||
Optional<Categoryattribute> findByAttributeId(@Param("attributeid") Integer attributeid);
|
||||
|
||||
/**
|
||||
* 检查分类下是否存在指定名称的属性
|
||||
* @param categoryid 分类ID
|
||||
* @param attributename 属性名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByCategoryidAndAttributename(Integer categoryid, String attributename);
|
||||
|
||||
/**
|
||||
* 根据分类ID和属性名称查询属性
|
||||
* @param categoryid 分类ID
|
||||
* @param attributename 属性名称
|
||||
* @return 属性对象
|
||||
*/
|
||||
Optional<Categoryattribute> findByCategoryidAndAttributename(Integer categoryid, String attributename);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Category;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface CategoryRepository extends JpaRepository<Category, Integer> {
|
||||
|
||||
/**
|
||||
* 根据分类名称查询分类信息
|
||||
* @param typename 分类名称
|
||||
* @return 返回符合条件的分类列表
|
||||
*/
|
||||
|
||||
List<Category> findByTypenameContaining(String typename);
|
||||
|
||||
/**
|
||||
* 检查分类名称是否存在
|
||||
* @param typename 分类名称
|
||||
* @return 返回是否存在
|
||||
*/
|
||||
boolean existsByTypename(String typename);
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties.Pageable;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -11,22 +17,80 @@ import java.util.List;
|
||||
public interface MessageRepository extends JpaRepository<Message, Integer> {
|
||||
|
||||
// 根据文章ID查询消息
|
||||
/**
|
||||
* 根据文章ID查询消息
|
||||
* @param articleid 文章ID
|
||||
* @return 文章下的消息列表
|
||||
*/
|
||||
List<Message> findByArticleid(Integer articleid);
|
||||
|
||||
// 查询所有父消息(回复的根消息)
|
||||
/**
|
||||
* 查询所有父消息(回复的根消息)
|
||||
* @return 根回复消息列表
|
||||
*/
|
||||
List<Message> findByParentidIsNull();
|
||||
|
||||
// 根据父消息ID查询回复
|
||||
/**
|
||||
* 根据父消息ID查询回复
|
||||
* @param parentid 父消息ID
|
||||
* @return 回复消息列表
|
||||
*/
|
||||
List<Message> findByParentid(Integer parentid);
|
||||
|
||||
// 根据昵称模糊查询消息
|
||||
/**
|
||||
* 根据昵称模糊查询消息
|
||||
* @param nickname 昵称关键词
|
||||
* @return 包含关键词的消息列表
|
||||
*/
|
||||
List<Message> findByNicknameContaining(String nickname);
|
||||
|
||||
// 查询指定文章下的所有父消息(根回复)
|
||||
@Query("SELECT m FROM Message m WHERE m.articleid = ?1 AND m.parentid IS NULL ORDER BY m.createdAt DESC")
|
||||
List<Message> findRootMessagesByArticleId(Integer articleId);
|
||||
|
||||
/**
|
||||
* 查询指定文章下的所有父消息(根回复)
|
||||
* @param articleId 文章ID
|
||||
* @return 根回复消息列表
|
||||
*/
|
||||
@Query("SELECT m FROM Message m WHERE m.articleid = :articleId AND m.parentid IS NULL ORDER BY m.createdAt DESC")
|
||||
List<Message> findRootMessagesByArticleId(@Param("articleId") Integer articleId);
|
||||
/**
|
||||
* 点赞数增加
|
||||
* @param messageId 消息ID
|
||||
*/
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE Message m SET m.likes = COALESCE(m.likes, 0) + 1 WHERE m.messageid = :messageId")
|
||||
void incrementLikes(@Param("messageId") Integer messageId);
|
||||
// 统计指定文章的评论数量
|
||||
@Query("SELECT COUNT(m) FROM Message m WHERE m.articleid = ?1")
|
||||
Long countByArticleId(Integer articleId);
|
||||
/**
|
||||
* 根据文章ID分页查询消息
|
||||
* @param articleid 文章ID
|
||||
* @param pageable 分页信息
|
||||
* @return 分页消息列表
|
||||
*/
|
||||
@Query("SELECT m FROM Message m WHERE m.articleid = :articleId ORDER BY m.createdAt DESC")
|
||||
Page<Message> findByArticleId(@Param("articleId") Integer articleId, PageRequest pageable);
|
||||
/**
|
||||
* 根据页查询消息
|
||||
* @param pageable 分页信息
|
||||
* @return 分页消息列表
|
||||
*/
|
||||
@Query("SELECT m FROM Message m WHERE m.articleid IS NULL ORDER BY m.createdAt DESC")
|
||||
Page<Message> findAllMessages(PageRequest pageable);
|
||||
/**
|
||||
* 统计指定文章下的回复消息数量
|
||||
* @param articleId 文章ID
|
||||
* @return 回复消息数量
|
||||
*/
|
||||
@Query("SELECT COUNT(m) FROM Message m WHERE m.articleid = :articleId AND m.parentid IS NULL")
|
||||
Integer countReplyByArticleId(@Param("articleId") Integer articleId);
|
||||
|
||||
/**
|
||||
* 统计指定文章id parentid为空的回复消息数量
|
||||
* @param articleId 文章ID
|
||||
* @return 回复消息数量
|
||||
*/
|
||||
@Query("SELECT COUNT(m) FROM Message m WHERE m.articleid IS NULL AND m.parentid IS NULL")
|
||||
Integer countReplyByArticleIdIsNull();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Nonsense;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface NonsenseRepository extends JpaRepository<Nonsense, Integer> {
|
||||
/**
|
||||
* 根据状态获取文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@Query("SELECT n FROM Nonsense n WHERE n.status = :status")
|
||||
List<Nonsense> findByStatus(@Param("status") Integer status);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.qf.myafterprojecy.repository;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface UsersRepository extends JpaRepository<Users, Long> {
|
||||
|
||||
/**
|
||||
* 根据用户名查询用户信息
|
||||
* @param username 用户名
|
||||
* @return 返回符合条件的用户对象
|
||||
*/
|
||||
Optional<Users> findByUsername(String username);
|
||||
|
||||
/**
|
||||
* 根据邮箱查询用户信息
|
||||
* @param email 邮箱
|
||||
* @return 返回符合条件的用户对象
|
||||
*/
|
||||
Optional<Users> findByEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据手机号查询用户信息
|
||||
* @param phone 手机号
|
||||
* @return 返回符合条件的用户对象
|
||||
*/
|
||||
Optional<Users> findByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 检查用户名是否存在
|
||||
* @param username 用户名
|
||||
* @return 返回是否存在
|
||||
*/
|
||||
boolean existsByUsername(String username);
|
||||
|
||||
/**
|
||||
* 检查邮箱是否存在
|
||||
* @param email 邮箱
|
||||
* @return 返回是否存在
|
||||
*/
|
||||
boolean existsByEmail(String email);
|
||||
|
||||
/**
|
||||
* 检查手机号是否存在
|
||||
* @param phone 手机号
|
||||
* @return 返回是否存在
|
||||
*/
|
||||
boolean existsByPhone(String phone);
|
||||
|
||||
/**
|
||||
* 根据角色查询用户列表
|
||||
* @param role 角色
|
||||
* @return 用户列表
|
||||
*/
|
||||
@Query("SELECT u FROM Users u WHERE u.role = :role")
|
||||
java.util.List<Users> findByRole(@Param("role") int role);
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
package com.qf.myafterprojecy.runner;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessageDto;
|
||||
import com.qf.myafterprojecy.repository.MessageRepository;
|
||||
import com.qf.myafterprojecy.service.IMessageService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 消息数据检查器,用于验证消息相关的业务代码是否正常工作
|
||||
*/
|
||||
@Component
|
||||
public class MessageDataChecker implements CommandLineRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessageDataChecker.class);
|
||||
|
||||
@Autowired
|
||||
private MessageRepository messageRepository;
|
||||
|
||||
@Autowired
|
||||
private IMessageService messageService;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
logger.info("===== 消息数据检查器开始运行 =====");
|
||||
|
||||
// 检查数据库中是否已有消息数据
|
||||
long count = messageRepository.count();
|
||||
logger.info("当前数据库中消息数量: {}", count);
|
||||
|
||||
// 如果没有消息数据,添加一些测试数据
|
||||
if (count == 0) {
|
||||
logger.info("数据库中没有消息数据,开始添加测试数据...");
|
||||
addTestMessages();
|
||||
}
|
||||
|
||||
// 测试查询方法
|
||||
testQueryMethods();
|
||||
|
||||
// 测试服务层方法
|
||||
testServiceMethods();
|
||||
|
||||
logger.info("===== 消息数据检查器运行结束 =====");
|
||||
}
|
||||
|
||||
private void addTestMessages() {
|
||||
// 添加第一篇文章的评论
|
||||
Message message1 = new Message();
|
||||
message1.setNickname("张三");
|
||||
message1.setEmail("zhangsan@example.com");
|
||||
message1.setContent("这是一篇很棒的文章!");
|
||||
message1.setCreatedAt(new Date());
|
||||
message1.setArticleid(1);
|
||||
message1.setParentid(null); // 根评论
|
||||
messageRepository.save(message1);
|
||||
|
||||
// 添加回复
|
||||
Message reply1 = new Message();
|
||||
reply1.setNickname("李四");
|
||||
reply1.setEmail("lisi@example.com");
|
||||
reply1.setContent("同意你的观点!");
|
||||
reply1.setCreatedAt(new Date());
|
||||
reply1.setArticleid(1);
|
||||
reply1.setParentid(message1.getMessageid()); // 回复第一篇评论
|
||||
messageRepository.save(reply1);
|
||||
|
||||
// 添加第二篇文章的评论
|
||||
Message message2 = new Message();
|
||||
message2.setNickname("王五");
|
||||
message2.setEmail("wangwu@example.com");
|
||||
message2.setContent("学到了很多东西,谢谢分享!");
|
||||
message2.setCreatedAt(new Date());
|
||||
message2.setArticleid(2);
|
||||
message2.setParentid(null);
|
||||
messageRepository.save(message2);
|
||||
|
||||
logger.info("成功添加了{}条测试消息数据", messageRepository.count());
|
||||
}
|
||||
|
||||
private void testQueryMethods() {
|
||||
logger.info("===== 测试Repository查询方法 =====");
|
||||
|
||||
// 测试根据文章ID查询
|
||||
List<Message> article1Messages = messageRepository.findByArticleid(1);
|
||||
logger.info("文章ID为1的消息数量: {}", article1Messages.size());
|
||||
|
||||
// 测试查询所有根消息
|
||||
List<Message> rootMessages = messageRepository.findByParentidIsNull();
|
||||
logger.info("根消息数量: {}", rootMessages.size());
|
||||
|
||||
// 测试根据昵称模糊查询
|
||||
List<Message> zhangMessages = messageRepository.findByNicknameContaining("张");
|
||||
logger.info("昵称包含'张'的消息数量: {}", zhangMessages.size());
|
||||
|
||||
// 测试统计文章评论数量
|
||||
Long article1Count = messageRepository.countByArticleId(1);
|
||||
logger.info("文章ID为1的评论数量: {}", article1Count);
|
||||
|
||||
// 如果有根消息,测试查询回复
|
||||
if (!rootMessages.isEmpty()) {
|
||||
Integer firstRootId = rootMessages.get(0).getMessageid();
|
||||
List<Message> replies = messageRepository.findByParentid(firstRootId);
|
||||
logger.info("消息ID为{}的回复数量: {}", firstRootId, replies.size());
|
||||
}
|
||||
}
|
||||
|
||||
private void testServiceMethods() {
|
||||
logger.info("===== 测试Service层方法 =====");
|
||||
|
||||
// 测试获取所有消息
|
||||
ResponseMessage<Iterable<Message>> allMessagesResponse = messageService.getAllMessages();
|
||||
logger.info("获取所有消息: 成功={}, 消息数量={}", allMessagesResponse.isSuccess(),
|
||||
((List<Message>)allMessagesResponse.getData()).size());
|
||||
|
||||
// 测试根据ID获取消息
|
||||
if (messageRepository.count() > 0) {
|
||||
Message firstMessage = messageRepository.findAll().iterator().next();
|
||||
Integer messageId = firstMessage.getMessageid();
|
||||
ResponseMessage<Message> messageResponse = messageService.getMessageById(messageId);
|
||||
logger.info("根据ID{}获取消息: 成功={}, 昵称={}", messageId,
|
||||
messageResponse.isSuccess(),
|
||||
messageResponse.getData() != null ? messageResponse.getData().getNickname() : "null");
|
||||
|
||||
// 测试获取指定文章的评论数量
|
||||
ResponseMessage<Long> countResponse = messageService.getMessageCountByArticleId(1);
|
||||
logger.info("获取文章ID为1的评论数量: 成功={}, 数量={}",
|
||||
countResponse.isSuccess(), countResponse.getData());
|
||||
|
||||
// 测试获取根消息
|
||||
ResponseMessage<List<Message>> rootResponse = messageService.getRootMessages();
|
||||
logger.info("获取根消息: 成功={}, 数量={}",
|
||||
rootResponse.isSuccess(),
|
||||
rootResponse.getData() != null ? rootResponse.getData().size() : 0);
|
||||
}
|
||||
|
||||
// 测试保存新消息
|
||||
MessageDto newMessage = new MessageDto();
|
||||
newMessage.setNickname("测试用户");
|
||||
newMessage.setEmail("test@example.com");
|
||||
newMessage.setContent("这是一条测试消息");
|
||||
newMessage.setArticleid(1);
|
||||
newMessage.setParentid(null);
|
||||
|
||||
ResponseMessage<Message> saveResponse = messageService.saveMessage(newMessage);
|
||||
logger.info("保存新消息: 成功={}, 消息ID={}",
|
||||
saveResponse.isSuccess(),
|
||||
saveResponse.getData() != null ? saveResponse.getData().getMessageid() : "null");
|
||||
|
||||
// 如果保存成功,测试删除
|
||||
if (saveResponse.isSuccess() && saveResponse.getData() != null) {
|
||||
Integer savedId = saveResponse.getData().getMessageid();
|
||||
ResponseMessage<Message> deleteResponse = messageService.deleteMessage(savedId);
|
||||
logger.info("删除消息ID{}: 成功={}", savedId, deleteResponse.isSuccess());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.pojo.Article;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArticleDto;
|
||||
import com.qf.myafterprojecy.repository.ArticleRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class ArticleService implements IArticleService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ArticleService.class);
|
||||
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Article> getArticleById(String id) {
|
||||
try {
|
||||
if (id == null || id.isEmpty()) {
|
||||
return ResponseMessage.failure("文章ID不能为空");
|
||||
}
|
||||
Article article = articleRepository.findById(Integer.parseInt(id))
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
// 暂时不增加浏览次数,以避免事务问题
|
||||
// articleRepository.incrementViewCount(id);
|
||||
|
||||
return ResponseMessage.success(article);
|
||||
} catch (Exception e) {
|
||||
log.error("获取文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("获取文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getAllArticles() {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findAll();
|
||||
return ResponseMessage.success(articles);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("获取文章列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> saveArticle(ArticleDto articleDto) {
|
||||
try {
|
||||
Article article = new Article();
|
||||
BeanUtils.copyProperties(articleDto, article);
|
||||
article.setCreatedAt(LocalDateTime.now());
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
article.setImg(articleDto.getImg() != null ? articleDto.getImg() : "");
|
||||
article.setStatus(articleDto.getStatus() != null ? articleDto.getStatus() : 0);
|
||||
|
||||
Article savedArticle = articleRepository.save(article);
|
||||
return ResponseMessage.success(savedArticle);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("保存文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("保存文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> updateArticle(Integer id, ArticleDto articleDto) {
|
||||
try {
|
||||
Article article = articleRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
BeanUtils.copyProperties(articleDto, article);
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
Article updatedArticle = articleRepository.save(article);
|
||||
return ResponseMessage.success(updatedArticle);
|
||||
} catch (Exception e) {
|
||||
log.error("更新文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("更新文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> deleteArticle(Integer id) {
|
||||
try {
|
||||
Article article = articleRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
article.setStatus(2); // 标记为已删除
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
articleRepository.save(article);
|
||||
|
||||
return ResponseMessage.success(null);
|
||||
} catch (Exception e) {
|
||||
log.error("删除文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("删除文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getArticlesByCategory(Integer categoryId) {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findPublishedByCategory(categoryId);
|
||||
return ResponseMessage.success(articles);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取分类文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("获取分类文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getMostViewedArticles() {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findMostViewed();
|
||||
return ResponseMessage.success(articles);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取热门文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.failure("获取热门文章失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,108 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Article;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArriclePageDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArticleDto;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IArticleService {
|
||||
ResponseMessage<Article> getArticleById(String id);
|
||||
|
||||
ResponseMessage<List<Article>> getAllArticles();
|
||||
|
||||
/**
|
||||
* 根据标题查询文章列表
|
||||
*
|
||||
* @param title 文章标题的一部分,用于模糊查询
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
ResponseMessage<List<Article>> getArticlesByTitle(String title);
|
||||
/**
|
||||
* 根据状态获取文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<List<Article>> getArticlesByStatus(Integer status);
|
||||
/**
|
||||
* 获取文章数量
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回文章数量
|
||||
*/
|
||||
ResponseMessage<Integer> getArticleCount(Integer status);
|
||||
/**
|
||||
* 创建新文章
|
||||
* 仅限AUTHOR角色用户访问
|
||||
*
|
||||
* @param articleDto 包含文章数据的DTO对象
|
||||
* @return 返回包含新创建文章信息的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<Article> saveArticle(ArticleDto articleDto);
|
||||
|
||||
/**
|
||||
* 更新指定ID的文章
|
||||
*
|
||||
* @param id 文章ID
|
||||
* @param articleDto 包含更新信息的ArticleDto对象
|
||||
* @return 返回包含操作结果的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<Article> updateArticle(Integer id, ArticleDto articleDto);
|
||||
|
||||
/**
|
||||
* 删除指定ID的文章
|
||||
*
|
||||
* @param id 文章ID
|
||||
* @return 返回包含操作结果的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<Article> deleteArticle(Integer id);
|
||||
|
||||
/**
|
||||
* 根据分类ID查询文章列表(兼容旧接口)
|
||||
*
|
||||
* @param typeid 分类ID
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
ResponseMessage<List<Article>> getArticlesByCategory(Integer typeid);
|
||||
|
||||
/**
|
||||
* 根据属性ID查询文章列表
|
||||
*
|
||||
* @param attributeid 属性ID
|
||||
* @return 返回符合查询条件的文章列表
|
||||
*/
|
||||
ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid);
|
||||
|
||||
/**
|
||||
* 根据属性ID查询最新文章列表
|
||||
*
|
||||
* @param attributeid 属性ID
|
||||
* @return 返回符合查询条件的最新文章列表
|
||||
*/
|
||||
ResponseMessage<List<Article>> getLatestArticlesByAttribute(Integer attributeid);
|
||||
|
||||
ResponseMessage<List<Article>> getMostViewedArticles();
|
||||
|
||||
/**
|
||||
* 增加文章浏览量
|
||||
*
|
||||
* @param id 文章ID
|
||||
* @return 返回包含更新后文章信息的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<Article> incrementViewCount(Integer id);
|
||||
/**
|
||||
* 获取已发布的文章列表
|
||||
* @return 返回包含已发布文章列表的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<List<Article>> getPublishedArticles();
|
||||
|
||||
/**
|
||||
* 根据状态分页查询文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @param page 页码,从0开始
|
||||
* @param size 每页大小
|
||||
* @return 返回包含分页文章列表的ResponseMessage对象
|
||||
*/
|
||||
ResponseMessage<Page<Article>> getArticlesByStatusWithPagination(ArriclePageDto arriclePageDto);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Categoryattribute;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ICategoryAttributeService {
|
||||
/**
|
||||
* 获取全部分类属性
|
||||
* @return 所有分类属性列表
|
||||
*/
|
||||
ResponseMessage<List<Categoryattribute>> getAllCategoryAttributes();
|
||||
|
||||
/**
|
||||
* 根据ID获取分类属性
|
||||
* @param id 属性ID
|
||||
* @return 分类属性信息
|
||||
*/
|
||||
ResponseMessage<Categoryattribute> getCategoryAttributeById(Integer id);
|
||||
|
||||
/**
|
||||
* 根据分类ID获取属性列表
|
||||
* @param categoryId 分类ID
|
||||
* @return 属性列表
|
||||
*/
|
||||
ResponseMessage<List<Categoryattribute>> getAttributesByCategoryId(Integer categoryId);
|
||||
|
||||
/**
|
||||
* 创建新的分类属性
|
||||
* @param dto 分类属性数据
|
||||
* @return 创建结果
|
||||
*/
|
||||
ResponseMessage<Categoryattribute> saveCategoryAttribute(CategoryAttributeDto dto);
|
||||
|
||||
/**
|
||||
* 更新分类属性
|
||||
* @param id 属性ID
|
||||
* @param dto 分类属性数据
|
||||
* @return 更新结果
|
||||
*/
|
||||
ResponseMessage<Categoryattribute> updateCategoryAttribute(Integer id, CategoryAttributeDto dto);
|
||||
|
||||
/**
|
||||
* 删除分类属性
|
||||
* @param id 属性ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
ResponseMessage<Boolean> deleteCategoryAttribute(Integer id);
|
||||
|
||||
/**
|
||||
* 检查分类下是否存在指定名称的属性
|
||||
* @param categoryId 分类ID
|
||||
* @param attributeName 属性名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
ResponseMessage<Boolean> existsByCategoryAndName(Integer categoryId, String attributeName);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Category;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ICategoryService {
|
||||
/**
|
||||
* 根据ID获取分类信息
|
||||
* @param id 分类ID
|
||||
* @return 返回分类信息
|
||||
*/
|
||||
ResponseMessage<Category> getCategoryById(Integer id);
|
||||
|
||||
/**
|
||||
* 获取所有分类列表
|
||||
* @return 返回分类列表
|
||||
*/
|
||||
ResponseMessage<List<Category>> getAllCategories();
|
||||
|
||||
/**
|
||||
* 保存新分类
|
||||
* @param categoryDto 分类数据传输对象
|
||||
* @return 返回保存结果
|
||||
*/
|
||||
ResponseMessage<Category> saveCategory(CategoryDto categoryDto);
|
||||
|
||||
/**
|
||||
* 更新分类信息
|
||||
* @param id 分类ID
|
||||
* @param categoryDto 分类数据传输对象
|
||||
* @return 返回更新结果
|
||||
*/
|
||||
ResponseMessage<Category> updateCategory(Integer id, CategoryDto categoryDto);
|
||||
|
||||
/**
|
||||
* 删除分类
|
||||
* @param id 分类ID
|
||||
* @return 返回删除结果
|
||||
*/
|
||||
ResponseMessage<Boolean> deleteCategory(Integer id);
|
||||
|
||||
/**
|
||||
* 根据分类名称搜索分类
|
||||
* @param typename 分类名称
|
||||
* @return 返回符合条件的分类列表
|
||||
*/
|
||||
ResponseMessage<List<Category>> searchCategoriesByTypename(String typename);
|
||||
}
|
||||
@@ -1,69 +1,99 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessageDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessagePageDto;
|
||||
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IMessageService {
|
||||
/**
|
||||
* 获取所有消息的方法
|
||||
* @return 返回一个ResponseMessage对象,其中包含一个可迭代的Message集合
|
||||
* ResponseMessage是响应消息的包装类,Iterable<Message>表示可迭代的消息集合
|
||||
*/
|
||||
/**
|
||||
* 获取所有消息的方法
|
||||
*
|
||||
* @return 返回一个ResponseMessage对象,其中包含一个可迭代的Message集合
|
||||
* ResponseMessage是响应消息的包装类,Iterable<Message>表示可迭代的消息集合
|
||||
*/
|
||||
ResponseMessage<Iterable<Message>> getAllMessages();
|
||||
/**
|
||||
* 根据消息ID获取消息的方法
|
||||
* @param id 消息的唯一标识符
|
||||
* @return ResponseMessage<Message> 包含消息的响应对象,其中Message为消息的具体内容
|
||||
*/
|
||||
/**
|
||||
* 分页
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
ResponseMessage<List<Message>> getMessagesByPage(MessagePageDto messagePageDto);
|
||||
/**
|
||||
* 获取回复消息条数 如果id为空获取文章id为空的消息条数
|
||||
* @param articleId 文章id
|
||||
* @return 回复消息条数
|
||||
*/
|
||||
ResponseMessage<Integer> getMessageCountByArticleId(Integer articleId);
|
||||
/**
|
||||
* 根据消息ID获取消息的方法
|
||||
*
|
||||
* @param id 消息的唯一标识符
|
||||
* @return ResponseMessage<Message> 包含消息的响应对象,其中Message为消息的具体内容
|
||||
*/
|
||||
ResponseMessage<Message> getMessageById(Integer id);
|
||||
/**
|
||||
* 保存消息的方法
|
||||
* @param message 消息数据传输对象,包含需要保存的消息信息
|
||||
* @return ResponseMessage<Message> 返回一个响应消息对象,包含操作结果和保存后的消息信息
|
||||
*/
|
||||
|
||||
/**
|
||||
* 保存消息的方法
|
||||
*
|
||||
* @param message 消息数据传输对象,包含需要保存的消息信息
|
||||
* @return ResponseMessage<Message> 返回一个响应消息对象,包含操作结果和保存后的消息信息
|
||||
*/
|
||||
ResponseMessage<Message> saveMessage(MessageDto message);
|
||||
/**
|
||||
* 根据消息ID删除消息的方法
|
||||
* @param id 要删除的消息ID
|
||||
* @return ResponseMessage<Message> 包含操作结果的响应消息,其中泛型Message表示被删除的消息内容
|
||||
*/
|
||||
|
||||
/**
|
||||
* 根据消息ID删除消息的方法
|
||||
*
|
||||
* @param id 要删除的消息ID
|
||||
* @return ResponseMessage<Message> 包含操作结果的响应消息,其中泛型Message表示被删除的消息内容
|
||||
*/
|
||||
ResponseMessage<Message> deleteMessage(Integer id);
|
||||
|
||||
|
||||
/**
|
||||
* 增加消息的点赞数
|
||||
*
|
||||
* @param id 消息ID
|
||||
* @return 包含操作结果的响应消息,其中泛型Message表示操作后的消息内容
|
||||
*/
|
||||
ResponseMessage<Message> likeMessage(Integer id);
|
||||
|
||||
// 新增方法
|
||||
/**
|
||||
* 根据文章ID查询消息
|
||||
*
|
||||
* @param articleId 文章ID
|
||||
* @return 消息列表
|
||||
*/
|
||||
ResponseMessage<List<Message>> getMessagesByArticleId(Integer articleId);
|
||||
|
||||
|
||||
/**
|
||||
* 查询所有父消息(根回复)
|
||||
*
|
||||
* @return 父消息列表
|
||||
*/
|
||||
ResponseMessage<List<Message>> getRootMessages();
|
||||
|
||||
|
||||
/**
|
||||
* 根据父消息ID查询回复
|
||||
*
|
||||
* @param parentId 父消息ID
|
||||
* @return 回复消息列表
|
||||
*/
|
||||
ResponseMessage<List<Message>> getRepliesByParentId(Integer parentId);
|
||||
|
||||
|
||||
/**
|
||||
* 根据昵称模糊查询消息
|
||||
*
|
||||
* @param nickname 昵称
|
||||
* @return 匹配的消息列表
|
||||
*/
|
||||
ResponseMessage<List<Message>> searchMessagesByNickname(String nickname);
|
||||
|
||||
/**
|
||||
* 获取指定文章的评论数量
|
||||
* @param articleId 文章ID
|
||||
* @return 评论数量
|
||||
*/
|
||||
ResponseMessage<Long> getMessageCountByArticleId(Integer articleId);
|
||||
|
||||
// 删除所有评论
|
||||
ResponseMessage<Void> deleteAllMessages();
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Nonsense;
|
||||
import com.qf.myafterprojecy.pojo.dto.NonsenseDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface INonsenseService {
|
||||
/**
|
||||
* 获取所有疯言疯语内容
|
||||
* @return 疯言疯语内容列表
|
||||
*/
|
||||
ResponseMessage<List<Nonsense>> getAllNonsense();
|
||||
|
||||
/**
|
||||
* 根据ID获取疯言疯语内容
|
||||
* @param id 疯言疯语内容ID
|
||||
* @return 疯言疯语内容
|
||||
*/
|
||||
ResponseMessage<Nonsense> getNonsenseById(Integer id);
|
||||
|
||||
/**
|
||||
* 根据状态获取疯言疯语内容
|
||||
* @param status 状态:0未发表 1已发表 2已删除
|
||||
* @return 疯言疯语内容列表
|
||||
*/
|
||||
ResponseMessage<List<Nonsense>> getNonsenseByStatus(Integer status);
|
||||
|
||||
/**
|
||||
* 更新疯言疯语内容状态
|
||||
* @param id 疯言疯语内容ID
|
||||
* @param status 新状态:0未发表 1已发表 2已删除
|
||||
* @return 更新结果
|
||||
*/
|
||||
ResponseMessage<Nonsense> updateNonsenseStatus(Integer id, Integer status);
|
||||
|
||||
/**
|
||||
* 保存疯言疯语内容
|
||||
* @param nonsenseDto 疯言疯语内容数据传输对象
|
||||
* @return 保存结果
|
||||
*/
|
||||
ResponseMessage<Nonsense> saveNonsense(NonsenseDto nonsenseDto);
|
||||
|
||||
/**
|
||||
* 更新疯言疯语内容
|
||||
* @param id 疯言疯语内容ID
|
||||
* @param nonsenseDto 疯言疯语内容数据传输对象
|
||||
* @return 更新结果
|
||||
*/
|
||||
ResponseMessage<Nonsense> updateNonsense(Integer id, NonsenseDto nonsenseDto);
|
||||
|
||||
/**
|
||||
* 删除疯言疯语内容
|
||||
* @param id 疯言疯语内容ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
ResponseMessage<Boolean> deleteNonsense(Integer id);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import com.qf.myafterprojecy.pojo.dto.UserDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IUserService {
|
||||
/**
|
||||
* 根据ID获取用户信息
|
||||
* @param id 用户ID
|
||||
* @return 返回用户信息
|
||||
*/
|
||||
ResponseMessage<Users> getUserById(Long id);
|
||||
|
||||
/**
|
||||
* 获取所有用户列表
|
||||
* @return 返回用户列表
|
||||
*/
|
||||
ResponseMessage<List<Users>> getAllUsers();
|
||||
|
||||
/**
|
||||
* 根据用户名获取用户信息
|
||||
* @param username 用户名
|
||||
* @return 返回用户信息
|
||||
*/
|
||||
ResponseMessage<Users> getUserByUsername(String username);
|
||||
|
||||
/**
|
||||
* 保存新用户
|
||||
* @param userDto 用户数据传输对象
|
||||
* @return 返回保存结果
|
||||
*/
|
||||
ResponseMessage<Users> saveUser(UserDto userDto);
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param id 用户ID
|
||||
* @param userDto 用户数据传输对象
|
||||
* @return 返回更新结果
|
||||
*/
|
||||
ResponseMessage<Users> updateUser(Long id, UserDto userDto);
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return 返回删除结果
|
||||
*/
|
||||
ResponseMessage<Boolean> deleteUser(Long id);
|
||||
|
||||
/**
|
||||
* 根据角色查询用户列表
|
||||
* @param role 角色
|
||||
* @return 用户列表
|
||||
*/
|
||||
ResponseMessage<List<Users>> getUsersByRole(int role);
|
||||
|
||||
/**
|
||||
* 检查用户名是否存在
|
||||
* @param username 用户名
|
||||
* @return 是否存在
|
||||
*/
|
||||
ResponseMessage<Boolean> existsByUsername(String username);
|
||||
|
||||
/**
|
||||
* 检查邮箱是否存在
|
||||
* @param email 邮箱
|
||||
* @return 是否存在
|
||||
*/
|
||||
ResponseMessage<Boolean> existsByEmail(String email);
|
||||
|
||||
/**
|
||||
* 检查手机号是否存在
|
||||
* @param phone 手机号
|
||||
* @return 是否存在
|
||||
*/
|
||||
ResponseMessage<Boolean> existsByPhone(String phone);
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Article;
|
||||
import com.qf.myafterprojecy.pojo.Categoryattribute;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArriclePageDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.ArticleDto;
|
||||
import com.qf.myafterprojecy.repository.ArticleRepository;
|
||||
import com.qf.myafterprojecy.repository.CategoryAttributeRepository;
|
||||
import com.qf.myafterprojecy.service.IArticleService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class ArticleService implements IArticleService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ArticleService.class);
|
||||
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
|
||||
@Autowired
|
||||
private CategoryAttributeRepository categoryAttributeRepository;
|
||||
|
||||
/**
|
||||
* 根据文章ID获取文章详情
|
||||
* @param id 文章ID
|
||||
* @return 返回包含文章详情的ResponseMessage对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Article> getArticleById(String id) {
|
||||
try {
|
||||
if (id == null || id.isEmpty()) {
|
||||
return ResponseMessage.badRequest("文章ID不能为空");
|
||||
}
|
||||
Article article = articleRepository.findById(Integer.parseInt(id))
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
// 文章浏览次数增加
|
||||
articleRepository.incrementViewCount(Integer.parseInt(id));
|
||||
|
||||
|
||||
return ResponseMessage.success(article, "获取文章成功");
|
||||
} catch (NumberFormatException e) {
|
||||
return ResponseMessage.badRequest("文章ID格式不正确");
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("文章不存在")) {
|
||||
return ResponseMessage.notFound("文章不存在");
|
||||
}
|
||||
log.error("获取文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取文章失败");
|
||||
} catch (Exception e) {
|
||||
log.error("获取文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取文章失败");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取文章数量
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回文章数量
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Integer> getArticleCount(Integer status) {
|
||||
try {
|
||||
if (status == null) {
|
||||
return ResponseMessage.badRequest("文章状态不能为空");
|
||||
}
|
||||
if (status < 0 || status > 2) {
|
||||
return ResponseMessage.badRequest("文章状态值必须在0到2之间");
|
||||
}
|
||||
Integer count = articleRepository.countByStatus(status);
|
||||
return ResponseMessage.success(count, "获取文章数量成功");
|
||||
} catch (Exception e) {
|
||||
log.error("获取文章数量失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取文章数量失败");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 根据状态获取文章列表
|
||||
* @param status 文章状态(0:未发表 1:已发表 2:已删除)
|
||||
* @return 返回包含文章列表的ResponseMessage对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getArticlesByStatus(Integer status) {
|
||||
try {
|
||||
if (status == null) {
|
||||
return ResponseMessage.badRequest("文章状态不能为空");
|
||||
}
|
||||
if (status < 0 || status > 2) {
|
||||
return ResponseMessage.badRequest("文章状态值必须在0到2之间");
|
||||
}
|
||||
List<Article> articles = articleRepository.findByStatus(status);
|
||||
return ResponseMessage.success(articles, "根据状态查询文章成功");
|
||||
} catch (Exception e) {
|
||||
log.error("根据状态查询文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("根据状态查询文章列表失败");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取已发布的文章列表
|
||||
* @return 返回包含已发布文章列表的ResponseMessage对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getPublishedArticles() {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findByStatus(1);
|
||||
return ResponseMessage.success(articles, "获取已发布文章列表成功");
|
||||
} catch (Exception e) {
|
||||
log.error("获取已发布文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取已发布文章列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Page<Article>> getArticlesByStatusWithPagination(ArriclePageDto arriclePageDto) {
|
||||
if (arriclePageDto.getPagenum() == null || arriclePageDto.getPagenum() < 0) {
|
||||
arriclePageDto.setPagenum(0); // 默认第一页
|
||||
}
|
||||
if (arriclePageDto.getPagesize() == null || arriclePageDto.getPagesize() <= 0 || arriclePageDto.getPagesize() > 100) {
|
||||
arriclePageDto.setPagesize(10); // 默认每页10条,最大100条
|
||||
}
|
||||
try {
|
||||
// 如果文章状态值是否在0到2之间则根据文章状态查询文章列表
|
||||
if (arriclePageDto.getStatus() < 0 || arriclePageDto.getStatus() > 2) {
|
||||
return ResponseMessage.badRequest("文章状态值必须在0到2之间");
|
||||
}
|
||||
PageRequest pageRequest = PageRequest.of(arriclePageDto.getPagenum(), arriclePageDto.getPagesize());
|
||||
// 如果文章分类ID不为空则根据文章分类ID查询文章列表
|
||||
if (arriclePageDto.getCategoryid() != null && arriclePageDto.getCategoryid() > 0) {
|
||||
// 如果文章分类ID不为空则根据文章分类ID查询文章列表
|
||||
List<Categoryattribute> categoryAttribute = categoryAttributeRepository.findByCategoryId(arriclePageDto.getCategoryid());
|
||||
if (categoryAttribute.isEmpty()) {
|
||||
return ResponseMessage.badRequest("分类下没有属性");
|
||||
}
|
||||
// 如果文章属性ID数组不为空则根据文章属性ID数组查询文章列表
|
||||
List<Integer> attributeids = categoryAttribute.stream().map(Categoryattribute::getAttributeid).collect(Collectors.toList());
|
||||
// 根据分类ID对应的属性ID数组分页查询文章列表
|
||||
Page<Article> articlePage = articleRepository.findByStatusWithPagination(arriclePageDto.getStatus(), attributeids, pageRequest);
|
||||
return ResponseMessage.success(articlePage, "根据分类ID分页查询文章成功");
|
||||
}
|
||||
// 如果文章属性ID不为空则根据文章属性ID查询文章列表
|
||||
if (arriclePageDto.getAttributeid() != null && arriclePageDto.getAttributeid() > 0) {
|
||||
Page<Article> articlePage = articleRepository.findByStatusWithPagination(arriclePageDto.getStatus(), arriclePageDto.getAttributeid(), pageRequest);
|
||||
return ResponseMessage.success(articlePage, "根据属性ID分页查询文章成功");
|
||||
}
|
||||
// 如果文章标题不为空则根据文章标题查询文章列表
|
||||
if (arriclePageDto.getTitle() != null && !arriclePageDto.getTitle().isEmpty()) {
|
||||
Page<Article> articlePage = articleRepository.findByStatusWithPagination(arriclePageDto.getStatus(), arriclePageDto.getTitle(), pageRequest);
|
||||
return ResponseMessage.success(articlePage, "根据标题分页查询文章成功");
|
||||
}
|
||||
Page<Article> articlePage = articleRepository.findByStatusWithPagination(arriclePageDto.getStatus(), pageRequest);
|
||||
return ResponseMessage.success(articlePage, "根据状态分页查询文章成功");
|
||||
} catch (Exception e) {
|
||||
log.error("根据状态分页查询文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("根据状态分页查询文章列表失败");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getArticlesByTitle(String title) {
|
||||
try {
|
||||
if (title == null || title.isEmpty()) {
|
||||
return ResponseMessage.badRequest("文章标题不能为空");
|
||||
}
|
||||
List<Article> articles = articleRepository.findByTitle(title);
|
||||
return ResponseMessage.success(articles, "根据标题查询文章成功");
|
||||
} catch (Exception e) {
|
||||
log.error("根据标题查询文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("根据标题查询文章列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getAllArticles() {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findAll();
|
||||
return ResponseMessage.success(articles, "获取文章列表成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取文章列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取文章列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> saveArticle(ArticleDto articleDto) {
|
||||
try {
|
||||
Article article = new Article();
|
||||
BeanUtils.copyProperties(articleDto, article);
|
||||
article.setCreatedAt(LocalDateTime.now());
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
article.setImg(articleDto.getImg() != null ? articleDto.getImg() : "");
|
||||
article.setStatus(articleDto.getStatus() != null ? articleDto.getStatus() : 0);
|
||||
|
||||
Article savedArticle = articleRepository.save(article);
|
||||
return ResponseMessage.save(true, savedArticle);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("保存文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("保存文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> updateArticle(Integer id, ArticleDto articleDto) {
|
||||
try {
|
||||
Article article = articleRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
BeanUtils.copyProperties(articleDto, article);
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
Article updatedArticle = articleRepository.save(article);
|
||||
return ResponseMessage.update(true, updatedArticle);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("文章不存在")) {
|
||||
return ResponseMessage.notFound("文章不存在");
|
||||
}
|
||||
log.error("更新文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新文章失败");
|
||||
} catch (Exception e) {
|
||||
log.error("更新文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> deleteArticle(Integer id) {
|
||||
try {
|
||||
Article article = articleRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
article.setStatus(2); // 标记为已删除
|
||||
article.setUpdatedAt(LocalDateTime.now());
|
||||
articleRepository.save(article);
|
||||
|
||||
return ResponseMessage.delete(true);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("文章不存在")) {
|
||||
return ResponseMessage.notFound("文章不存在");
|
||||
}
|
||||
log.error("删除文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("删除文章失败");
|
||||
} catch (Exception e) {
|
||||
log.error("删除文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("删除文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getArticlesByCategory(Integer categoryId) {
|
||||
try {
|
||||
// 可以考虑查询该分类下的所有属性,然后获取相关文章
|
||||
log.warn("使用了旧接口getArticlesByCategory,请考虑迁移到getArticlesByAttribute");
|
||||
return ResponseMessage.success(articleRepository.findPublishedByAttribute(categoryId), "获取分类文章成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取分类文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getArticlesByAttribute(Integer attributeid) {
|
||||
try {
|
||||
if (attributeid == null || attributeid <= 0) {
|
||||
return ResponseMessage.badRequest("属性ID无效");
|
||||
}
|
||||
|
||||
// 验证属性是否存在
|
||||
if (!categoryAttributeRepository.existsById(attributeid)) {
|
||||
return ResponseMessage.notFound("属性不存在");
|
||||
}
|
||||
|
||||
List<Article> articles = articleRepository.findPublishedByAttribute(attributeid);
|
||||
return ResponseMessage.success(articles, "获取属性文章成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取属性文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取属性文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加文章浏览量
|
||||
*
|
||||
* @param id 文章ID
|
||||
* @return 返回包含更新后文章信息的ResponseMessage对象
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Article> incrementViewCount(Integer id) {
|
||||
try {
|
||||
Article article = articleRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("文章不存在"));
|
||||
|
||||
articleRepository.incrementViewCount(id);
|
||||
|
||||
return ResponseMessage.success(article, "增加文章浏览量成功");
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("文章不存在")) {
|
||||
return ResponseMessage.notFound("文章不存在");
|
||||
}
|
||||
log.error("增加文章浏览量失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("增加文章浏览量失败");
|
||||
} catch (Exception e) {
|
||||
log.error("增加文章浏览量失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("增加文章浏览量失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getLatestArticlesByAttribute(Integer attributeid) {
|
||||
try {
|
||||
if (attributeid == null || attributeid <= 0) {
|
||||
return ResponseMessage.badRequest("属性ID无效");
|
||||
}
|
||||
|
||||
// 验证属性是否存在
|
||||
if (!categoryAttributeRepository.existsById(attributeid)) {
|
||||
return ResponseMessage.notFound("属性不存在");
|
||||
}
|
||||
|
||||
List<Article> articles = articleRepository.findLatestByAttribute(attributeid);
|
||||
return ResponseMessage.success(articles, "获取最新属性文章成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取最新属性文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取最新属性文章失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Article>> getMostViewedArticles() {
|
||||
try {
|
||||
List<Article> articles = articleRepository.findMostViewed();
|
||||
return ResponseMessage.success(articles, "获取热门文章成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取热门文章失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取热门文章失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Categoryattribute;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryAttributeDto;
|
||||
import com.qf.myafterprojecy.repository.CategoryAttributeRepository;
|
||||
import com.qf.myafterprojecy.service.ICategoryAttributeService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CategoryAttributeService implements ICategoryAttributeService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CategoryAttributeService.class);
|
||||
|
||||
@Autowired
|
||||
private CategoryAttributeRepository categoryAttributeRepository;
|
||||
|
||||
/**
|
||||
* 获取全部分类属性
|
||||
* @return 所有分类属性列表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Categoryattribute>> getAllCategoryAttributes() {
|
||||
try {
|
||||
List<Categoryattribute> attributes = categoryAttributeRepository.findAll();
|
||||
return ResponseMessage.success(attributes, "获取所有分类属性成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取所有分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取所有分类属性失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取分类属性
|
||||
* @param id 属性ID
|
||||
* @return 分类属性信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Categoryattribute> getCategoryAttributeById(Integer id) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("属性ID无效");
|
||||
}
|
||||
|
||||
Categoryattribute attribute = categoryAttributeRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("分类属性不存在"));
|
||||
|
||||
return ResponseMessage.success(attribute, "获取分类属性成功");
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("分类属性不存在")) {
|
||||
return ResponseMessage.notFound("分类属性不存在");
|
||||
}
|
||||
log.error("获取分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类属性失败");
|
||||
} catch (Exception e) {
|
||||
log.error("获取分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类属性失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据分类ID获取属性列表
|
||||
* @param categoryId 分类ID
|
||||
* @return 属性列表
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Categoryattribute>> getAttributesByCategoryId(Integer categoryId) {
|
||||
try {
|
||||
if (categoryId == null || categoryId <= 0) {
|
||||
return ResponseMessage.badRequest("分类ID无效");
|
||||
}
|
||||
|
||||
List<Categoryattribute> attributes = categoryAttributeRepository.findByCategoryId(categoryId);
|
||||
return ResponseMessage.success(attributes, "获取分类属性列表成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取分类属性列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类属性列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存分类属性
|
||||
* @param dto 分类属性DTO
|
||||
* @return 保存结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Categoryattribute> saveCategoryAttribute(CategoryAttributeDto dto) {
|
||||
try {
|
||||
// 检查属性名称是否已存在于该分类下
|
||||
if (categoryAttributeRepository.existsByCategoryidAndAttributename(
|
||||
dto.getCategoryid(), dto.getAttributename())) {
|
||||
return ResponseMessage.badRequest("该分类下已存在同名属性");
|
||||
}
|
||||
|
||||
Categoryattribute attribute = new Categoryattribute();
|
||||
BeanUtils.copyProperties(dto, attribute);
|
||||
|
||||
Categoryattribute savedAttribute = categoryAttributeRepository.save(attribute);
|
||||
log.info("成功创建分类属性: {}, 分类ID: {}",
|
||||
savedAttribute.getAttributename(), savedAttribute.getCategoryid());
|
||||
|
||||
return ResponseMessage.save(true, savedAttribute);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("保存分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("保存分类属性失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新分类属性
|
||||
* @param id 属性ID
|
||||
* @param dto 分类属性DTO
|
||||
* @return 更新结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Categoryattribute> updateCategoryAttribute(Integer id, CategoryAttributeDto dto) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("属性ID无效");
|
||||
}
|
||||
|
||||
Categoryattribute attribute = categoryAttributeRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("分类属性不存在"));
|
||||
|
||||
// 如果修改了属性名称,检查新名称是否已存在
|
||||
if (!attribute.getAttributename().equals(dto.getAttributename()) &&
|
||||
categoryAttributeRepository.existsByCategoryidAndAttributename(
|
||||
dto.getCategoryid(), dto.getAttributename())) {
|
||||
return ResponseMessage.badRequest("该分类下已存在同名属性");
|
||||
}
|
||||
|
||||
BeanUtils.copyProperties(dto, attribute);
|
||||
attribute.setAttributeid(id); // 确保ID不变
|
||||
|
||||
Categoryattribute updatedAttribute = categoryAttributeRepository.save(attribute);
|
||||
log.info("成功更新分类属性: ID={}, 名称={}",
|
||||
updatedAttribute.getAttributeid(), updatedAttribute.getAttributename());
|
||||
|
||||
return ResponseMessage.update(true, updatedAttribute);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("分类属性不存在")) {
|
||||
return ResponseMessage.notFound("分类属性不存在");
|
||||
}
|
||||
log.error("更新分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新分类属性失败");
|
||||
} catch (Exception e) {
|
||||
log.error("更新分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新分类属性失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除分类属性
|
||||
* @param id 属性ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Boolean> deleteCategoryAttribute(Integer id) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("属性ID无效");
|
||||
}
|
||||
|
||||
if (!categoryAttributeRepository.existsById(id)) {
|
||||
return ResponseMessage.notFound("分类属性不存在");
|
||||
}
|
||||
|
||||
categoryAttributeRepository.deleteById(id);
|
||||
log.info("成功删除分类属性: ID={}", id);
|
||||
|
||||
return ResponseMessage.delete(true);
|
||||
} catch (Exception e) {
|
||||
log.error("删除分类属性失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("删除分类属性失败");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查分类属性是否存在
|
||||
* @param categoryId 分类ID
|
||||
* @param attributeName 属性名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Boolean> existsByCategoryAndName(Integer categoryId, String attributeName) {
|
||||
try {
|
||||
if (categoryId == null || categoryId <= 0 || attributeName == null || attributeName.isEmpty()) {
|
||||
return ResponseMessage.badRequest("参数无效");
|
||||
}
|
||||
|
||||
boolean exists = categoryAttributeRepository.existsByCategoryidAndAttributename(
|
||||
categoryId, attributeName);
|
||||
|
||||
return ResponseMessage.success(exists, "检查分类属性成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("检查分类属性是否存在失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("检查分类属性是否存在失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Category;
|
||||
import com.qf.myafterprojecy.pojo.dto.CategoryDto;
|
||||
import com.qf.myafterprojecy.repository.CategoryRepository;
|
||||
import com.qf.myafterprojecy.service.ICategoryService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class CategoryService implements ICategoryService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CategoryService.class);
|
||||
|
||||
@Autowired
|
||||
private CategoryRepository categoryRepository;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<Category> getCategoryById(Integer id) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("分类ID无效");
|
||||
}
|
||||
Category category = categoryRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("分类不存在"));
|
||||
return ResponseMessage.success(category, "获取分类成功");
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("分类不存在")) {
|
||||
return ResponseMessage.notFound("分类不存在");
|
||||
}
|
||||
log.error("获取分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类失败");
|
||||
} catch (Exception e) {
|
||||
log.error("获取分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Category>> getAllCategories() {
|
||||
try {
|
||||
List<Category> categories = categoryRepository.findAll();
|
||||
return ResponseMessage.success(categories, "获取分类列表成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("获取分类列表失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("获取分类列表失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Category> saveCategory(CategoryDto categoryDto) {
|
||||
try {
|
||||
// 检查分类名称是否已存在
|
||||
if (categoryRepository.existsByTypename(categoryDto.getTypename())) {
|
||||
return ResponseMessage.badRequest( "分类名称已存在");
|
||||
}
|
||||
|
||||
Category category = new Category();
|
||||
BeanUtils.copyProperties(categoryDto, category);
|
||||
category.setCreatedAt(LocalDateTime.now());
|
||||
category.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
Category savedCategory = categoryRepository.save(category);
|
||||
return ResponseMessage.save(true, savedCategory);
|
||||
} catch (DataAccessException e) {
|
||||
log.error("保存分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("保存分类失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Category> updateCategory(Integer id, CategoryDto categoryDto) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("分类ID无效");
|
||||
}
|
||||
|
||||
Category category = categoryRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("分类不存在"));
|
||||
|
||||
// 如果修改了分类名称,检查新名称是否已存在
|
||||
if (!category.getTypename().equals(categoryDto.getTypename()) &&
|
||||
categoryRepository.existsByTypename(categoryDto.getTypename())) {
|
||||
return ResponseMessage.badRequest("分类名称已存在");
|
||||
}
|
||||
|
||||
BeanUtils.copyProperties(categoryDto, category);
|
||||
category.setUpdatedAt(LocalDateTime.now());
|
||||
|
||||
Category updatedCategory = categoryRepository.save(category);
|
||||
return ResponseMessage.update(true, updatedCategory);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("分类不存在")) {
|
||||
return ResponseMessage.notFound("分类不存在");
|
||||
}
|
||||
log.error("更新分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新分类失败");
|
||||
} catch (Exception e) {
|
||||
log.error("更新分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("更新分类失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Boolean> deleteCategory(Integer id) {
|
||||
try {
|
||||
if (id == null || id <= 0) {
|
||||
return ResponseMessage.badRequest("分类ID无效");
|
||||
}
|
||||
|
||||
if (!categoryRepository.existsById(id)) {
|
||||
return ResponseMessage.notFound("分类不存在");
|
||||
}
|
||||
|
||||
// 注意:实际项目中可能需要先检查是否有文章引用该分类
|
||||
// 如果有,可能需要先处理文章或者禁止删除
|
||||
categoryRepository.deleteById(id);
|
||||
return ResponseMessage.delete(true);
|
||||
} catch (Exception e) {
|
||||
log.error("删除分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("删除分类失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResponseMessage<List<Category>> searchCategoriesByTypename(String typename) {
|
||||
try {
|
||||
if (typename == null || typename.trim().isEmpty()) {
|
||||
return ResponseMessage.badRequest("分类名称不能为空");
|
||||
}
|
||||
|
||||
List<Category> categories = categoryRepository.findByTypenameContaining(typename);
|
||||
return ResponseMessage.success(categories, "搜索分类成功");
|
||||
} catch (DataAccessException e) {
|
||||
log.error("搜索分类失败: {}", e.getMessage());
|
||||
return ResponseMessage.error("搜索分类失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,20 @@
|
||||
package com.qf.myafterprojecy.service;
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Message;
|
||||
import com.qf.myafterprojecy.pojo.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessageDto;
|
||||
import com.qf.myafterprojecy.pojo.dto.MessagePageDto;
|
||||
import com.qf.myafterprojecy.repository.MessageRepository;
|
||||
import com.qf.myafterprojecy.service.IMessageService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties.Pageable;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -16,11 +22,13 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class MessageService implements IMessageService {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MessageService.class);
|
||||
|
||||
|
||||
@Autowired
|
||||
private MessageRepository messageRepository;
|
||||
|
||||
@@ -29,10 +37,10 @@ public class MessageService implements IMessageService {
|
||||
try {
|
||||
logger.info("查询所有消息");
|
||||
Iterable<Message> messages = messageRepository.findAll();
|
||||
return ResponseMessage.success(messages, "查询成功", true);
|
||||
return ResponseMessage.success(messages, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("查询所有消息失败", e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,74 +48,76 @@ public class MessageService implements IMessageService {
|
||||
public ResponseMessage<Message> getMessageById(Integer id) {
|
||||
if (id == null || id <= 0) {
|
||||
logger.warn("获取消息时ID无效: {}", id);
|
||||
return ResponseMessage.failure("消息ID无效");
|
||||
return ResponseMessage.badRequest("消息ID无效");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
logger.info("根据ID查询消息: {}", id);
|
||||
Optional<Message> messageOptional = messageRepository.findById(id);
|
||||
if (messageOptional.isPresent()) {
|
||||
return ResponseMessage.success(messageOptional.get(), "查询成功", true);
|
||||
return ResponseMessage.success(messageOptional.get(), "查询成功");
|
||||
} else {
|
||||
logger.warn("未找到ID为{}的消息", id);
|
||||
return ResponseMessage.failure("未找到指定消息");
|
||||
return ResponseMessage.notFound("未找到指定消息");
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("查询消息失败: {}", id, e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Message> saveMessage(MessageDto messageDto) {
|
||||
// 参数校验
|
||||
if (messageDto == null) {
|
||||
logger.warn("保存消息时参数为空");
|
||||
throw new IllegalArgumentException("MessageDto cannot be null");
|
||||
}
|
||||
|
||||
|
||||
// 业务逻辑校验
|
||||
if (StringUtils.isEmpty(messageDto.getContent())) {
|
||||
logger.warn("保存消息时内容为空");
|
||||
throw new IllegalArgumentException("Message content cannot be empty");
|
||||
}
|
||||
|
||||
|
||||
if (StringUtils.isEmpty(messageDto.getNickname())) {
|
||||
logger.warn("保存消息时昵称为空");
|
||||
throw new IllegalArgumentException("Message nickname cannot be empty");
|
||||
}
|
||||
|
||||
|
||||
// 调用Repository保存数据
|
||||
try {
|
||||
logger.info("保存消息: {}", messageDto.getNickname());
|
||||
Message message = new Message();
|
||||
BeanUtils.copyProperties(messageDto, message);
|
||||
message.setCreatedAt(new Date()); // 设置创建时间
|
||||
|
||||
message.setLikes(0); // 设置点赞数初始值为0
|
||||
|
||||
// 如果是回复,确保parentid有效
|
||||
if (messageDto.getParentid() != null && messageDto.getParentid() > 0) {
|
||||
if (!messageRepository.existsById(messageDto.getParentid())) {
|
||||
logger.warn("回复的父消息不存在: {}", messageDto.getParentid());
|
||||
return ResponseMessage.failure("回复的父消息不存在");
|
||||
return ResponseMessage.notFound("回复的父消息不存在");
|
||||
}
|
||||
}
|
||||
|
||||
Message savedMessage = messageRepository.save(message);
|
||||
logger.info("消息保存成功: {}", savedMessage.getMessageid());
|
||||
return ResponseMessage.success(savedMessage, "保存成功", true);
|
||||
return ResponseMessage.save(true, savedMessage);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("保存消息失败", e);
|
||||
return ResponseMessage.failure("保存消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("保存消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Message> deleteMessage(Integer id) {
|
||||
if (id == null || id <= 0) {
|
||||
logger.warn("删除消息时ID无效: {}", id);
|
||||
return ResponseMessage.failure("消息ID无效");
|
||||
return ResponseMessage.badRequest("消息ID无效");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
logger.info("删除消息: {}", id);
|
||||
if (messageRepository.existsById(id)) {
|
||||
@@ -119,14 +129,14 @@ public class MessageService implements IMessageService {
|
||||
logger.info("同时删除了{}条回复消息", replies.size());
|
||||
}
|
||||
logger.info("消息删除成功: {}", id);
|
||||
return ResponseMessage.success(null, "删除成功", true);
|
||||
return ResponseMessage.delete(true);
|
||||
} else {
|
||||
logger.warn("未找到要删除的消息: {}", id);
|
||||
return ResponseMessage.failure("未找到要删除的消息");
|
||||
return ResponseMessage.notFound("未找到要删除的消息");
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("删除消息失败: {}", id, e);
|
||||
return ResponseMessage.failure("删除消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("删除消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,16 +144,16 @@ public class MessageService implements IMessageService {
|
||||
public ResponseMessage<List<Message>> getMessagesByArticleId(Integer articleId) {
|
||||
if (articleId == null || articleId <= 0) {
|
||||
logger.warn("根据文章ID查询消息时ID无效: {}", articleId);
|
||||
return ResponseMessage.failure("文章ID无效");
|
||||
return ResponseMessage.badRequest("文章ID无效");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
logger.info("根据文章ID查询消息: {}", articleId);
|
||||
List<Message> messages = messageRepository.findByArticleid(articleId);
|
||||
return ResponseMessage.success(messages, "查询成功", true);
|
||||
return ResponseMessage.success(messages, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据文章ID查询消息失败: {}", articleId, e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,10 +162,10 @@ public class MessageService implements IMessageService {
|
||||
try {
|
||||
logger.info("查询所有根消息");
|
||||
List<Message> messages = messageRepository.findByParentidIsNull();
|
||||
return ResponseMessage.success(messages, "查询成功", true);
|
||||
return ResponseMessage.success(messages, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("查询根消息失败", e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,16 +173,34 @@ public class MessageService implements IMessageService {
|
||||
public ResponseMessage<List<Message>> getRepliesByParentId(Integer parentId) {
|
||||
if (parentId == null || parentId <= 0) {
|
||||
logger.warn("根据父消息ID查询回复时ID无效: {}", parentId);
|
||||
return ResponseMessage.failure("父消息ID无效");
|
||||
return ResponseMessage.badRequest("父消息ID无效");
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("根据父消息ID查询回复: {}", parentId);
|
||||
List<Message> replies = messageRepository.findByParentid(parentId);
|
||||
return ResponseMessage.success(replies, "查询成功", true);
|
||||
return ResponseMessage.success(replies, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("查询回复消息失败: {}", parentId, e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 点赞数增加
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Message> likeMessage(Integer id) {
|
||||
if (id == null || id <= 0) {
|
||||
logger.warn("点赞消息时ID无效: {}", id);
|
||||
return ResponseMessage.badRequest("消息ID无效");
|
||||
}
|
||||
try {
|
||||
logger.info("点赞消息: {}", id);
|
||||
messageRepository.incrementLikes(id);
|
||||
Message likedMessage = messageRepository.findById(id).orElse(null);
|
||||
return ResponseMessage.success(likedMessage, "点赞成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("点赞消息失败: {}", id, e);
|
||||
return ResponseMessage.error("点赞消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,33 +208,79 @@ public class MessageService implements IMessageService {
|
||||
public ResponseMessage<List<Message>> searchMessagesByNickname(String nickname) {
|
||||
if (StringUtils.isEmpty(nickname)) {
|
||||
logger.warn("根据昵称查询消息时昵称为空");
|
||||
return ResponseMessage.failure("昵称不能为空");
|
||||
return ResponseMessage.badRequest("昵称不能为空");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
logger.info("根据昵称查询消息: {}", nickname);
|
||||
List<Message> messages = messageRepository.findByNicknameContaining(nickname);
|
||||
return ResponseMessage.success(messages, "查询成功", true);
|
||||
return ResponseMessage.success(messages, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据昵称查询消息失败: {}", nickname, e);
|
||||
return ResponseMessage.failure("查询消息失败:" + e.getMessage());
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 删除所有评论
|
||||
@Override
|
||||
public ResponseMessage<Long> getMessageCountByArticleId(Integer articleId) {
|
||||
if (articleId == null || articleId <= 0) {
|
||||
logger.warn("获取文章评论数量时ID无效: {}", articleId);
|
||||
return ResponseMessage.failure("文章ID无效");
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResponseMessage<Void> deleteAllMessages() {
|
||||
try {
|
||||
logger.info("删除所有消息");
|
||||
messageRepository.deleteAll();
|
||||
return ResponseMessage.delete(true);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("删除所有消息失败", e);
|
||||
return ResponseMessage.error("删除消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ResponseMessage<List<Message>> getMessagesByPage(MessagePageDto messagePageDto) {
|
||||
if (messagePageDto == null) {
|
||||
logger.warn("分页查询消息时参数为空");
|
||||
return ResponseMessage.badRequest("分页参数不能为空");
|
||||
}
|
||||
if (messagePageDto.getPageNum() == null) {
|
||||
logger.warn("分页查询消息时页码无效: {}", messagePageDto.getPageNum());
|
||||
return ResponseMessage.badRequest("页码无效");
|
||||
}
|
||||
if (messagePageDto.getPageSize() == null || messagePageDto.getPageSize() <= 0) {
|
||||
logger.warn("分页查询消息时每页数量无效: {}", messagePageDto.getPageSize());
|
||||
return ResponseMessage.badRequest("每页数量无效");
|
||||
}
|
||||
try {
|
||||
// 如何文章id为空,默认根据分页基础信息查询消息
|
||||
PageRequest pageable = PageRequest.of(messagePageDto.getPageNum(), messagePageDto.getPageSize());
|
||||
if (messagePageDto.getArticleid() != null && messagePageDto.getArticleid() > 0) {
|
||||
// 如果文章ID存在,根据文章ID查询消息
|
||||
Page<Message> messagePage = messageRepository.findByArticleId(messagePageDto.getArticleid(), pageable);
|
||||
return ResponseMessage.success(messagePage.getContent(), "查询成功");
|
||||
}
|
||||
// 如果文章ID不存在,根据分页基础信息查询所有消息
|
||||
Page<Message> messagePage = messageRepository.findAllMessages(pageable);
|
||||
return ResponseMessage.success(messagePage.getContent(), "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("分页查询消息失败: {}", messagePageDto, e);
|
||||
return ResponseMessage.error("查询消息失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
// 获取回复消息条数 如果id为空获取文章id为空的消息条数
|
||||
@Override
|
||||
public ResponseMessage<Integer> getMessageCountByArticleId(Integer articleId) {
|
||||
|
||||
try {
|
||||
logger.info("获取文章评论数量: {}", articleId);
|
||||
Long count = messageRepository.countByArticleId(articleId);
|
||||
return ResponseMessage.success(count, "查询成功", true);
|
||||
logger.info("获取文章回复数量: {}", articleId);
|
||||
if (articleId == null || articleId <= 0) {
|
||||
Integer count = messageRepository.countReplyByArticleIdIsNull();
|
||||
return ResponseMessage.success(count, "查询成功");
|
||||
}
|
||||
Integer count = messageRepository.countReplyByArticleId(articleId);
|
||||
return ResponseMessage.success(count, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("获取文章评论数量失败: {}", articleId, e);
|
||||
return ResponseMessage.failure("查询评论数量失败:" + e.getMessage());
|
||||
logger.error("获取文章回复数量失败: {}", articleId, e);
|
||||
return ResponseMessage.error("查询回复数量失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Nonsense;
|
||||
import com.qf.myafterprojecy.pojo.dto.NonsenseDto;
|
||||
import com.qf.myafterprojecy.repository.NonsenseRepository;
|
||||
import com.qf.myafterprojecy.service.INonsenseService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class NonsenseService implements INonsenseService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(NonsenseService.class);
|
||||
|
||||
@Autowired
|
||||
private NonsenseRepository nonsenseRepository;
|
||||
|
||||
@Override
|
||||
public ResponseMessage<List<Nonsense>> getAllNonsense() {
|
||||
try {
|
||||
// 获取所有疯言疯语内容,但在API层面只返回已发表(1)的内容
|
||||
List<Nonsense> allNonsense = nonsenseRepository.findAll();
|
||||
|
||||
return new ResponseMessage<>(200, "获取成功", allNonsense, true);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("获取所有疯言疯语内容失败", e);
|
||||
return new ResponseMessage<>(500, "数据库查询异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("获取所有疯言疯语内容失败", e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Nonsense> getNonsenseById(Integer id) {
|
||||
try {
|
||||
Optional<Nonsense> nonsenseOptional = nonsenseRepository.findById(id);
|
||||
if (nonsenseOptional.isPresent()) {
|
||||
Nonsense nonsense = nonsenseOptional.get();
|
||||
logger.info("获取ID为{}的疯言疯语内容成功,状态: {}", id, nonsense.getStatus());
|
||||
return new ResponseMessage<>(200, "获取成功", nonsense, true);
|
||||
} else {
|
||||
logger.warn("未找到ID为{}的疯言疯语内容", id);
|
||||
return new ResponseMessage<>(404, "未找到指定疯言疯语内容", null, false);
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据ID查询疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "数据库查询异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("根据ID查询疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<List<Nonsense>> getNonsenseByStatus(Integer status) {
|
||||
try {
|
||||
// 验证状态值是否有效
|
||||
if (status < 0 || status > 2) {
|
||||
logger.warn("无效的状态值: {}", status);
|
||||
return new ResponseMessage<>(400, "无效的状态值,必须是0(未发表)、1(已发表)或2(已删除)", null, false);
|
||||
}
|
||||
|
||||
List<Nonsense> nonsenseList = nonsenseRepository.findByStatus(status);
|
||||
// 根据状态过滤
|
||||
return new ResponseMessage<>(200, "获取成功", nonsenseList, true);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据状态获取疯言疯语内容失败,状态: {}", status, e);
|
||||
return new ResponseMessage<>(500, "数据库查询异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("根据状态获取疯言疯语内容失败,状态: {}", status, e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseMessage<Nonsense> updateNonsenseStatus(Integer id, Integer status) {
|
||||
try {
|
||||
// 验证状态值是否有效
|
||||
if (status < 0 || status > 2) {
|
||||
logger.warn("无效的状态值: {} 用于ID为{}的疯言疯语内容", status, id);
|
||||
return new ResponseMessage<>(400, "无效的状态值,必须是0(未发表)、1(已发表)或2(已删除)", null, false);
|
||||
}
|
||||
|
||||
Optional<Nonsense> nonsenseOptional = nonsenseRepository.findById(id);
|
||||
if (nonsenseOptional.isPresent()) {
|
||||
Nonsense nonsense = nonsenseOptional.get();
|
||||
Integer oldStatus = nonsense.getStatus();
|
||||
nonsense.setStatus(status);
|
||||
|
||||
Nonsense updatedNonsense = nonsenseRepository.save(nonsense);
|
||||
logger.info("更新疯言疯语内容状态成功,ID: {}, 旧状态: {}, 新状态: {}", id, oldStatus, status);
|
||||
return new ResponseMessage<>(200, "状态更新成功", updatedNonsense, true);
|
||||
} else {
|
||||
logger.warn("更新状态失败,未找到ID为{}的疯言疯语内容", id);
|
||||
return new ResponseMessage<>(404, "未找到指定疯言疯语内容", null, false);
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("更新疯言疯语内容状态失败,ID: {}, 状态: {}", id, status, e);
|
||||
return new ResponseMessage<>(500, "数据库操作异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("更新疯言疯语内容状态失败,ID: {}, 状态: {}", id, status, e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseMessage<Nonsense> saveNonsense(NonsenseDto nonsenseDto) {
|
||||
try {
|
||||
Nonsense nonsense = new Nonsense();
|
||||
BeanUtils.copyProperties(nonsenseDto, nonsense);
|
||||
|
||||
// 设置创建时间
|
||||
if (nonsense.getTime() == null) {
|
||||
nonsense.setTime(new Date());
|
||||
}
|
||||
|
||||
// 设置默认状态为未发表(0),如果DTO中未提供状态值
|
||||
if (nonsense.getStatus() == null) {
|
||||
nonsense.setStatus(0);
|
||||
}
|
||||
|
||||
Nonsense savedNonsense = nonsenseRepository.save(nonsense);
|
||||
logger.info("保存疯言疯语内容成功,ID: {}, 状态: {}", savedNonsense.getId(), savedNonsense.getStatus());
|
||||
return new ResponseMessage<>(200, "保存成功", savedNonsense, true);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("保存疯言疯语内容失败", e);
|
||||
return new ResponseMessage<>(500, "数据库操作异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("保存疯言疯语内容失败", e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseMessage<Nonsense> updateNonsense(Integer id, NonsenseDto nonsenseDto) {
|
||||
try {
|
||||
Optional<Nonsense> nonsenseOptional = nonsenseRepository.findById(id);
|
||||
if (nonsenseOptional.isPresent()) {
|
||||
Nonsense nonsense = nonsenseOptional.get();
|
||||
// 只有当DTO中提供了status值时才更新
|
||||
if (nonsenseDto.getStatus() != null) {
|
||||
logger.info("更新疯言疯语内容状态,ID: {}, 新状态: {}", id, nonsenseDto.getStatus());
|
||||
}
|
||||
BeanUtils.copyProperties(nonsenseDto, nonsense, "id");
|
||||
|
||||
Nonsense updatedNonsense = nonsenseRepository.save(nonsense);
|
||||
logger.info("更新疯言疯语内容成功,ID: {}, 当前状态: {}", id, updatedNonsense.getStatus());
|
||||
return new ResponseMessage<>(200, "更新成功", updatedNonsense, true);
|
||||
} else {
|
||||
logger.warn("更新失败,未找到ID为{}的疯言疯语内容", id);
|
||||
return new ResponseMessage<>(404, "未找到指定疯言疯语内容", null, false);
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("更新疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "数据库操作异常", null, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("更新疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public ResponseMessage<Boolean> deleteNonsense(Integer id) {
|
||||
try {
|
||||
if (nonsenseRepository.existsById(id)) {
|
||||
// 先将状态设置为已删除(2)
|
||||
Nonsense nonsense = nonsenseRepository.findById(id).get();
|
||||
nonsense.setStatus(2);
|
||||
nonsenseRepository.save(nonsense);
|
||||
|
||||
// 物理删除
|
||||
// nonsenseRepository.deleteById(id);
|
||||
logger.info("删除疯言疯语内容成功,ID: {}", id);
|
||||
return new ResponseMessage<>(200, "删除成功", true, true);
|
||||
} else {
|
||||
logger.warn("删除失败,未找到ID为{}的疯言疯语内容", id);
|
||||
return new ResponseMessage<>(404, "未找到指定疯言疯语内容", false, false);
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("删除疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "数据库操作异常", false, false);
|
||||
} catch (Exception e) {
|
||||
logger.error("删除疯言疯语内容失败,ID: {}", id, e);
|
||||
return new ResponseMessage<>(500, "服务器内部错误", false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
package com.qf.myafterprojecy.service.impl;
|
||||
|
||||
import com.qf.myafterprojecy.exceptopn.ResponseMessage;
|
||||
import com.qf.myafterprojecy.pojo.Users;
|
||||
import com.qf.myafterprojecy.pojo.dto.UserDto;
|
||||
import com.qf.myafterprojecy.repository.UsersRepository;
|
||||
import com.qf.myafterprojecy.service.IUserService;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class UserService implements IUserService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||
|
||||
@Autowired
|
||||
private UsersRepository usersRepository;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Users> getUserById(Long id) {
|
||||
try {
|
||||
Optional<Users> userOptional = usersRepository.findById(id);
|
||||
if (userOptional.isPresent()) {
|
||||
return ResponseMessage.success(userOptional.get(), "获取用户成功");
|
||||
} else {
|
||||
return ResponseMessage.notFound("用户不存在");
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("获取用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("获取用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<List<Users>> getAllUsers() {
|
||||
try {
|
||||
List<Users> users = usersRepository.findAll();
|
||||
return ResponseMessage.success(users, "获取所有用户成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("获取所有用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("获取所有用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Users> getUserByUsername(String username) {
|
||||
try {
|
||||
Optional<Users> userOptional = usersRepository.findByUsername(username);
|
||||
if (userOptional.isPresent()) {
|
||||
return ResponseMessage.success(userOptional.get(), "获取用户成功");
|
||||
} else {
|
||||
return ResponseMessage.notFound("用户不存在");
|
||||
}
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据用户名获取用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("根据用户名获取用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public ResponseMessage<Users> saveUser(UserDto userDto) {
|
||||
try {
|
||||
// 检查用户名是否已存在
|
||||
if (usersRepository.existsByUsername(userDto.getUsername())) {
|
||||
return ResponseMessage.badRequest("用户名已存在");
|
||||
}
|
||||
|
||||
// 检查邮箱是否已存在
|
||||
if (usersRepository.existsByEmail(userDto.getEmail())) {
|
||||
return ResponseMessage.badRequest("邮箱已存在");
|
||||
}
|
||||
|
||||
// 检查手机号是否已存在
|
||||
if (usersRepository.existsByPhone(userDto.getPhone())) {
|
||||
return ResponseMessage.badRequest("手机号已存在");
|
||||
}
|
||||
|
||||
// 创建新用户
|
||||
Users user = new Users();
|
||||
BeanUtils.copyProperties(userDto, user);
|
||||
// 使用密码编码器加密密码
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
user.setCreateTime(LocalDateTime.now());
|
||||
|
||||
// 保存用户
|
||||
Users savedUser = usersRepository.save(user);
|
||||
return ResponseMessage.save(true, savedUser);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("保存用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("保存用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public ResponseMessage<Users> updateUser(Long id, UserDto userDto) {
|
||||
try {
|
||||
Optional<Users> userOptional = usersRepository.findById(id);
|
||||
if (!userOptional.isPresent()) {
|
||||
return ResponseMessage.notFound("用户不存在");
|
||||
}
|
||||
|
||||
Users user = userOptional.get();
|
||||
|
||||
// 检查用户名是否被其他用户使用
|
||||
if (!user.getUsername().equals(userDto.getUsername()) && usersRepository.existsByUsername(userDto.getUsername())) {
|
||||
return ResponseMessage.badRequest("用户名已存在");
|
||||
}
|
||||
|
||||
// 检查邮箱是否被其他用户使用
|
||||
if (!user.getEmail().equals(userDto.getEmail()) && usersRepository.existsByEmail(userDto.getEmail())) {
|
||||
return ResponseMessage.badRequest("邮箱已存在");
|
||||
}
|
||||
|
||||
// 检查手机号是否被其他用户使用
|
||||
if (!user.getPhone().equals(userDto.getPhone()) && usersRepository.existsByPhone(userDto.getPhone())) {
|
||||
return ResponseMessage.badRequest("手机号已存在");
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
BeanUtils.copyProperties(userDto, user);
|
||||
|
||||
// 如果提供了新密码,则进行加密
|
||||
if (userDto.getPassword() != null && !userDto.getPassword().isEmpty()) {
|
||||
user.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
}
|
||||
Users updatedUser = usersRepository.save(user);
|
||||
return ResponseMessage.update(true, updatedUser);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("更新用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("更新用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public ResponseMessage<Boolean> deleteUser(Long id) {
|
||||
try {
|
||||
if (!usersRepository.existsById(id)) {
|
||||
return ResponseMessage.notFound("用户不存在");
|
||||
}
|
||||
|
||||
usersRepository.deleteById(id);
|
||||
return ResponseMessage.delete(true);
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("删除用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("删除用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<List<Users>> getUsersByRole(int role) {
|
||||
try {
|
||||
List<Users> users = usersRepository.findByRole(role);
|
||||
return ResponseMessage.success(users, "根据角色获取用户成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("根据角色获取用户异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("根据角色获取用户未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Boolean> existsByUsername(String username) {
|
||||
try {
|
||||
boolean exists = usersRepository.existsByUsername(username);
|
||||
return ResponseMessage.success(exists, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("检查用户名存在性异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("检查用户名存在性未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Boolean> existsByEmail(String email) {
|
||||
try {
|
||||
boolean exists = usersRepository.existsByEmail(email);
|
||||
return ResponseMessage.success(exists, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("检查邮箱存在性异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("检查邮箱存在性未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseMessage<Boolean> existsByPhone(String phone) {
|
||||
try {
|
||||
boolean exists = usersRepository.existsByPhone(phone);
|
||||
return ResponseMessage.success(exists, "查询成功");
|
||||
} catch (DataAccessException e) {
|
||||
logger.error("检查手机号存在性异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("数据库访问异常");
|
||||
} catch (Exception e) {
|
||||
logger.error("检查手机号存在性未知异常: {}", e.getMessage());
|
||||
return ResponseMessage.error("服务器异常");
|
||||
}
|
||||
}
|
||||
}
|
||||
103
src/main/java/com/qf/myafterprojecy/utils/JwtUtils.java
Normal file
103
src/main/java/com/qf/myafterprojecy/utils/JwtUtils.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.qf.myafterprojecy.utils;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* JWT工具类,用于生成和验证token
|
||||
*/
|
||||
@Component
|
||||
public class JwtUtils {
|
||||
|
||||
@Value("${jwt.secret:default_secret_key_for_development}")
|
||||
private String secret;
|
||||
|
||||
@Value("${jwt.expiration:86400000}")
|
||||
private long expiration;
|
||||
|
||||
@Value("${jwt.token-prefix:Bearer}")
|
||||
private String tokenPrefix;
|
||||
|
||||
/**
|
||||
* 从token中获取用户名
|
||||
*/
|
||||
public String getUsernameFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getSubject);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中获取过期时间
|
||||
*/
|
||||
public Date getExpirationDateFromToken(String token) {
|
||||
return getClaimFromToken(token, Claims::getExpiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从token中获取指定的claim
|
||||
*/
|
||||
public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
|
||||
final Claims claims = getAllClaimsFromToken(token);
|
||||
return claimsResolver.apply(claims);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token中的所有claims
|
||||
*/
|
||||
private Claims getAllClaimsFromToken(String token) {
|
||||
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查token是否过期
|
||||
*/
|
||||
private Boolean isTokenExpired(String token) {
|
||||
final Date expiration = getExpirationDateFromToken(token);
|
||||
return expiration.before(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成token
|
||||
*/
|
||||
public String generateToken(UserDetails userDetails) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("authorities", userDetails.getAuthorities());
|
||||
return doGenerateToken(claims, userDetails.getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成token的核心方法
|
||||
*/
|
||||
private String doGenerateToken(Map<String, Object> claims, String subject) {
|
||||
return Jwts.builder()
|
||||
.setClaims(claims)
|
||||
.setSubject(subject)
|
||||
.setIssuedAt(new Date(System.currentTimeMillis()))
|
||||
.setExpiration(new Date(System.currentTimeMillis() + expiration))
|
||||
.signWith(SignatureAlgorithm.HS512, secret)
|
||||
.compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
*/
|
||||
public Boolean validateToken(String token, UserDetails userDetails) {
|
||||
final String username = getUsernameFromToken(token);
|
||||
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token前缀
|
||||
*/
|
||||
public String getTokenPrefix() {
|
||||
return tokenPrefix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{"properties": [{
|
||||
"name": "Content-Type,",
|
||||
"type": "java.lang.String",
|
||||
"description": "A description for 'Content-Type,'"
|
||||
}]}
|
||||
68
src/main/resources/application-dev.properties
Normal file
68
src/main/resources/application-dev.properties
Normal file
@@ -0,0 +1,68 @@
|
||||
# ====================================================================
|
||||
# 开发环境配置文件
|
||||
# 说明:此配置用于本地开发和调试,只包含开发环境特定配置
|
||||
# 通用配置请参考主配置文件 application.properties
|
||||
# ====================================================================
|
||||
|
||||
# 应用基本配置 - 开发特定
|
||||
server.port=7071
|
||||
|
||||
# ====================================================================
|
||||
# 数据库与JPA配置 - 开发用
|
||||
# ====================================================================
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/webproject?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 数据库连接池配置(开发环境简化版)
|
||||
spring.datasource.hikari.maximum-pool-size=5
|
||||
spring.datasource.hikari.minimum-idle=2
|
||||
|
||||
# JPA配置(开发环境使用update以便自动创建/更新表结构)
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.show-sql=false
|
||||
spring.jpa.properties.hibernate.format_sql=false
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
|
||||
|
||||
# ====================================================================
|
||||
# JWT 配置 - 开发用(方便调试,密钥较短,过期时间短)
|
||||
# ====================================================================
|
||||
jwt.secret=devSecretKey2024ForLocalDevelopment
|
||||
jwt.expiration=3600000
|
||||
# 1小时过期,方便调试
|
||||
jwt.header=Authorization
|
||||
jwt.token-prefix=Bearer
|
||||
|
||||
# ====================================================================
|
||||
# 安全与CORS配置 - 开发用
|
||||
# ====================================================================
|
||||
# CORS配置(开发环境允许所有本地前端访问)
|
||||
cors.allowed-origins=http://localhost:3000,http://localhost:8080,http://localhost:5173
|
||||
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
|
||||
cors.allowed-headers=*
|
||||
cors.allow-credentials=true
|
||||
|
||||
# ====================================================================
|
||||
# 日志配置 - 开发用(详细日志便于调试)
|
||||
# ====================================================================
|
||||
logging.level.root=INFO
|
||||
logging.level.com.qf.myafterprojecy=DEBUG
|
||||
logging.level.org.springframework=INFO
|
||||
logging.level.org.hibernate.SQL=DEBUG
|
||||
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
||||
|
||||
# ====================================================================
|
||||
# 开发环境特有配置
|
||||
# ====================================================================
|
||||
# 热部署配置
|
||||
spring.devtools.restart.enabled=true
|
||||
spring.devtools.restart.additional-paths=src/main/java
|
||||
# 解决DevTools重启时丢失profile配置的问题
|
||||
spring.devtools.restart.poll-interval=2s
|
||||
spring.devtools.restart.quiet-period=1s
|
||||
spring.devtools.restart.exclude=static/**,public/**
|
||||
|
||||
# Actuator配置(开发环境开放更多端点便于调试)
|
||||
management.endpoints.web.exposure.include=*
|
||||
management.endpoint.health.show-details=always
|
||||
70
src/main/resources/application-prod.properties
Normal file
70
src/main/resources/application-prod.properties
Normal file
@@ -0,0 +1,70 @@
|
||||
# ====================================================================
|
||||
# 生产环境配置文件
|
||||
# 说明:此配置用于生产环境部署,敏感信息从环境变量读取
|
||||
# ====================================================================
|
||||
|
||||
# 应用基本配置 - 生产特定
|
||||
server.port=7070
|
||||
|
||||
# ====================================================================
|
||||
# 数据库与JPA配置 - 生产用
|
||||
# ====================================================================
|
||||
spring.datasource.url=${DB_URL:jdbc:mysql://mysql:3306/webproject?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai}
|
||||
spring.datasource.username=${DB_USERNAME:root}
|
||||
spring.datasource.password=${DB_PASSWORD:root}
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 数据库连接池配置(生产环境优化版)
|
||||
spring.datasource.hikari.maximum-pool-size=20
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.idle-timeout=300000
|
||||
spring.datasource.hikari.connection-timeout=20000
|
||||
spring.datasource.hikari.max-lifetime=1200000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
spring.datasource.hikari.pool-name=WebProjectHikariCP
|
||||
|
||||
# JPA配置(生产环境禁用自动DDL,避免意外修改表结构)
|
||||
spring.jpa.hibernate.ddl-auto=create
|
||||
spring.jpa.show-sql=false
|
||||
spring.jpa.properties.hibernate.format_sql=false
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
|
||||
spring.jpa.open-in-view=false
|
||||
|
||||
# JPA性能优化配置
|
||||
spring.jpa.properties.hibernate.jdbc.batch_size=30
|
||||
spring.jpa.properties.hibernate.order_inserts=true
|
||||
spring.jpa.properties.hibernate.order_updates=true
|
||||
|
||||
# ====================================================================
|
||||
# JWT 配置 - 生产用(敏感信息从环境变量读取)
|
||||
# ====================================================================
|
||||
jwt.secret=${JWT_SECRET:}
|
||||
jwt.expiration=${JWT_EXPIRATION:86400000}
|
||||
jwt.header=Authorization
|
||||
jwt.token-prefix=Bearer
|
||||
|
||||
# ====================================================================
|
||||
# 安全与CORS配置 - 生产用
|
||||
# ====================================================================
|
||||
# CORS配置(生产环境限制为具体域名)
|
||||
cors.allowed-origins=http://qf1121.top,https://qf1121.top,http://www.qf1121.top,https://www.qf1121.top
|
||||
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
|
||||
cors.allowed-headers=*
|
||||
cors.allow-credentials=true
|
||||
cors.max-age=3600
|
||||
|
||||
# ====================================================================
|
||||
# 日志配置 - 生产用(精简日志,提高性能)
|
||||
# ====================================================================
|
||||
logging.level.root=WARN
|
||||
logging.level.com.qf.myafterprojecy=INFO
|
||||
logging.level.org.springframework.security=WARN
|
||||
logging.level.org.hibernate.SQL=ERROR
|
||||
logging.file.name=logs/web_project.log
|
||||
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
# ====================================================================
|
||||
# API与应用配置 - 生产用
|
||||
# ====================================================================
|
||||
# Actuator配置(生产环境限制访问)
|
||||
management.endpoints.web.exposure.include=health,info
|
||||
management.endpoint.health.show-details=when_authorized
|
||||
@@ -1,110 +1,43 @@
|
||||
# 应用服务 WEB 访问端口
|
||||
server.port=8080
|
||||
# ====================================================================
|
||||
# 应用基本配置 - 通用配置
|
||||
# ====================================================================
|
||||
# 环境激活配置
|
||||
# 说明:默认激活开发环境,生产环境部署时应通过命令行参数或环境变量覆盖
|
||||
spring.profiles.active=dev
|
||||
server.port=7070
|
||||
# 应用名称(通用配置)
|
||||
spring.application.name=web_project
|
||||
|
||||
# 数据库配置
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/webproject?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&createDatabaseIfNotExist=true
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
# 数据库连接池优化配置
|
||||
spring.datasource.hikari.maximum-pool-size=10
|
||||
spring.datasource.hikari.minimum-idle=5
|
||||
spring.datasource.hikari.idle-timeout=300000
|
||||
spring.datasource.hikari.connection-timeout=20000
|
||||
spring.datasource.hikari.max-lifetime=1200000
|
||||
spring.datasource.hikari.connection-test-query=SELECT 1
|
||||
spring.datasource.hikari.pool-name=WebProjectHikariCP
|
||||
|
||||
# JPA配置 - 生产环境建议将ddl-auto改为none
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.show-sql=false
|
||||
spring.jpa.properties.hibernate.format_sql=true
|
||||
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
|
||||
spring.jpa.open-in-view=false
|
||||
# JPA性能优化配置
|
||||
spring.jpa.properties.hibernate.jdbc.batch_size=30
|
||||
spring.jpa.properties.hibernate.order_inserts=true
|
||||
spring.jpa.properties.hibernate.order_updates=true
|
||||
# 暂时禁用Hibernate二级缓存和查询缓存
|
||||
# spring.jpa.properties.hibernate.cache.use_second_level_cache=true
|
||||
# spring.jpa.properties.hibernate.cache.use_query_cache=true
|
||||
|
||||
# 缓存配置
|
||||
# spring.cache.type=redis
|
||||
# spring.cache.redis.time-to-live=1800000
|
||||
# spring.cache.redis.key-prefix=CACHE_
|
||||
# spring.cache.redis.use-key-prefix=true
|
||||
# spring.cache.redis.cache-null-values=false
|
||||
|
||||
# Redis配置
|
||||
# spring.redis.host=localhost
|
||||
# spring.redis.port=6379
|
||||
# spring.redis.password=123456
|
||||
# spring.redis.database=0
|
||||
# spring.redis.timeout=10000ms
|
||||
# Redis连接池优化配置
|
||||
#spring.redis.lettuce.pool.max-active=8
|
||||
#spring.redis.lettuce.pool.max-wait=10000ms
|
||||
#spring.redis.lettuce.pool.max-idle=8
|
||||
#spring.redis.lettuce.pool.min-idle=2
|
||||
#spring.redis.lettuce.shutdown-timeout=100ms
|
||||
|
||||
# 日志配置
|
||||
logging.level.root=INFO
|
||||
logging.level.com.qf.myafterprojecy=DEBUG
|
||||
logging.level.org.springframework.security=INFO
|
||||
logging.level.org.hibernate.SQL=WARN
|
||||
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
||||
# 日志文件配置
|
||||
logging.file.name=logs/web_project.log
|
||||
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
# Actuator配置 - 生产环境建议限制暴露的端点
|
||||
management.endpoints.web.exposure.include=health,info,metrics,prometheus
|
||||
management.endpoint.health.show-details=when_authorized
|
||||
management.metrics.export.prometheus.enabled=true
|
||||
|
||||
# JWT配置 - 生产环境应使用更安全的密钥和环境变量
|
||||
jwt.secret=mySecretKey
|
||||
jwt.expiration=86400000
|
||||
jwt.header=Authorization
|
||||
jwt.token-prefix=Bearer
|
||||
|
||||
# CORS配置 - 生产环境应限制允许的源
|
||||
cors.allowed-origins=http://localhost:3000
|
||||
cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS
|
||||
cors.allowed-headers=*,
|
||||
Content-Type,
|
||||
X-Requested-With,
|
||||
accept,
|
||||
Origin,
|
||||
Access-Control-Request-Method,
|
||||
Access-Control-Request-Headers,
|
||||
Authorization
|
||||
cors.allow-credentials=true
|
||||
cors.max-age=3600
|
||||
|
||||
# 安全配置增强
|
||||
security.basic.enabled=false
|
||||
security.ignored=/css/**,/js/**,/images/**,/favicon.ico
|
||||
|
||||
# 生产环境建议配置
|
||||
# server.ssl.key-store=classpath:keystore.p12
|
||||
# server.ssl.key-store-password=password
|
||||
# server.ssl.key-store-type=PKCS12
|
||||
# server.ssl.key-alias=tomcat
|
||||
|
||||
# ====================================================================
|
||||
# 会话与编码配置 - 通用配置
|
||||
# ====================================================================
|
||||
# 会话配置
|
||||
server.servlet.session.timeout=30m
|
||||
server.session.tracking-modes=cookie
|
||||
|
||||
# 国际化配置
|
||||
#spring.mvc.locale-resolver=fixed
|
||||
#spring.mvc.locale=zh_CN
|
||||
#
|
||||
## 响应编码配置
|
||||
#spring.http.encoding.charset=UTF-8
|
||||
#spring.http.encoding.enabled=true
|
||||
#spring.http.encoding.force=true
|
||||
spring.web.locale=zh_CN
|
||||
spring.messages.encoding=UTF-8
|
||||
|
||||
# 响应编码配置(通用,所有环境保持一致)
|
||||
server.servlet.encoding.charset=UTF-8
|
||||
server.servlet.encoding.force=true
|
||||
server.servlet.encoding.force-request=true
|
||||
server.servlet.encoding.force-response=true
|
||||
server.servlet.encoding.enabled=true
|
||||
|
||||
# ====================================================================
|
||||
# API与应用配置 - 通用配置
|
||||
# ====================================================================
|
||||
# API 文档配置(通用)
|
||||
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
|
||||
|
||||
# 应用性能优化配置(通用)
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
spring.main.lazy-initialization=false
|
||||
|
||||
# ====================================================================
|
||||
# 说明:环境特定的配置(如数据库、JWT、CORS等)已移至对应的环境配置文件中
|
||||
# - 开发环境:application-dev.properties
|
||||
# - 生产环境:application-prod.properties
|
||||
# ====================================================================
|
||||
|
||||
Reference in New Issue
Block a user