feat: 添加UTF-8编码支持并优化DTO验证
refactor: 重构用户服务密码更新逻辑 fix: 删除不再使用的MarkdownDto类 style: 清理日志文件并优化日志配置 build: 更新pom.xml配置以支持UTF-8编码 docs: 更新application.properties配置文档
This commit is contained in:
3193
logs/web_project.log
3193
logs/web_project.log
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
logs/web_project.log.2025-10-28.0.gz
Normal file
BIN
logs/web_project.log.2025-10-28.0.gz
Normal file
Binary file not shown.
BIN
logs/web_project.log.2025-10-29.0.gz
Normal file
BIN
logs/web_project.log.2025-10-29.0.gz
Normal file
Binary file not shown.
12
pom.xml
12
pom.xml
@@ -138,6 +138,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>
|
||||
@@ -149,6 +150,17 @@
|
||||
</executions>
|
||||
</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>
|
||||
|
||||
@@ -3,11 +3,40 @@ package com.qf.myafterprojecy;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
|
||||
/**
|
||||
* Spring Security配置类
|
||||
@@ -61,8 +62,10 @@ public class SecurityConfig {
|
||||
.antMatchers(HttpMethod.GET,"/api/markdowns/**").permitAll()
|
||||
.antMatchers(HttpMethod.GET,"/api/articles/**").permitAll()
|
||||
.antMatchers(HttpMethod.GET,"/api/messages/**").permitAll()
|
||||
.antMatchers(HttpMethod.GET,"/api/categories/**").permitAll()
|
||||
// 公开post请求
|
||||
.antMatchers(HttpMethod.POST,"/api/messages/**").permitAll()
|
||||
.antMatchers(HttpMethod.POST,"/api/users/**").permitAll()
|
||||
// 管理员才能访问的路径
|
||||
.antMatchers("/api/admin/**").hasRole("ADMIN")
|
||||
// 其他所有请求都需要认证
|
||||
@@ -72,6 +75,15 @@ public class SecurityConfig {
|
||||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
|
||||
// 确保Spring Security不会添加额外的CharacterEncodingFilter
|
||||
// 因为我们在CharacterEncodingConfig中已经配置了自定义的过滤器
|
||||
http.addFilterBefore((request, response, chain) -> {
|
||||
// 确保响应使用UTF-8编码
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.setContentType("text/html;charset=UTF-8");
|
||||
chain.doFilter(request, response);
|
||||
}, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,7 @@ public class AuthController {
|
||||
|
||||
try {
|
||||
// 创建认证令牌
|
||||
UsernamePasswordAuthenticationToken authenticationToken =
|
||||
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
|
||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
|
||||
|
||||
// 执行认证
|
||||
Authentication authentication = authenticationManager.authenticate(authenticationToken);
|
||||
@@ -78,12 +77,11 @@ public class AuthController {
|
||||
|
||||
// 获取认证后的用户信息
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
|
||||
// 构建返回数据
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("username", userDetails.getUsername());
|
||||
data.put("authorities", userDetails.getAuthorities());
|
||||
data.put("message", "登录成功");
|
||||
// data.put("message", "登录成功");
|
||||
|
||||
return ResponseMessage.success(data, "登录成功");
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
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;
|
||||
@@ -20,16 +17,22 @@ public class ArticleDto {
|
||||
|
||||
private String img;
|
||||
|
||||
private Integer viewCount;
|
||||
|
||||
private Integer likes;
|
||||
|
||||
private Integer status;
|
||||
|
||||
// Getters and Setters
|
||||
@NotBlank(message = "Markdown内容不能为空")
|
||||
private String markdownscontent;
|
||||
|
||||
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() {
|
||||
@@ -48,12 +51,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() {
|
||||
@@ -63,4 +66,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public class CategoryAttributeDto {
|
||||
private Integer attributeid;
|
||||
|
||||
@NotNull(message = "分类ID不能为空")
|
||||
private Integer categoryid;
|
||||
@@ -12,6 +13,14 @@ public class CategoryAttributeDto {
|
||||
private String attributename;
|
||||
|
||||
// Getters and Setters
|
||||
public Integer getAttributeid() {
|
||||
return attributeid;
|
||||
}
|
||||
|
||||
public void setAttributeid(Integer attributeid) {
|
||||
this.attributeid = attributeid;
|
||||
}
|
||||
|
||||
public Integer getCategoryid() {
|
||||
return categoryid;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class CategoryDto {
|
||||
private Integer typeid;
|
||||
|
||||
@NotBlank(message = "分类名称不能为空")
|
||||
private String typename;
|
||||
|
||||
private String description;
|
||||
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// Getters and Setters
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.qf.myafterprojecy.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
@Data
|
||||
public class MarkdownDto {
|
||||
@NotBlank(message = "Markdown内容不能为空")
|
||||
private String markdownscontent;
|
||||
|
||||
public String getMarkdownscontent() {
|
||||
return markdownscontent;
|
||||
}
|
||||
|
||||
public void setMarkdownscontent(String markdownscontent) {
|
||||
this.markdownscontent = markdownscontent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,6 +19,8 @@ public class MessageDto {
|
||||
|
||||
private Integer articleid;
|
||||
|
||||
private Integer likes;
|
||||
|
||||
public Integer getReplyid() {
|
||||
return replyid;
|
||||
}
|
||||
@@ -26,6 +28,7 @@ public class MessageDto {
|
||||
public void setReplyid(Integer replyid) {
|
||||
this.replyid = replyid;
|
||||
}
|
||||
|
||||
public Integer getMessageid() {
|
||||
return messageid;
|
||||
}
|
||||
@@ -81,4 +84,12 @@ public class MessageDto {
|
||||
public void setArticleid(Integer articleid) {
|
||||
this.articleid = articleid;
|
||||
}
|
||||
|
||||
public Integer getLikes() {
|
||||
return likes;
|
||||
}
|
||||
|
||||
public void setLikes(Integer likes) {
|
||||
this.likes = likes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.qf.myafterprojecy.pojo.dto;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class UserDto {
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
private String username;
|
||||
|
||||
@@ -15,9 +17,16 @@ public class UserDto {
|
||||
@NotBlank(message = "手机号不能为空")
|
||||
private String phone;
|
||||
|
||||
@NotBlank(message = "角色不能为空")
|
||||
private int role;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
@@ -57,5 +66,4 @@ public class UserDto {
|
||||
public void setRole(int role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -147,7 +147,10 @@ public class UserService implements IUserService {
|
||||
// 更新用户信息
|
||||
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) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// package com.qf.myafterprojecy.util;
|
||||
|
||||
// import org.slf4j.Logger;
|
||||
// import org.slf4j.LoggerFactory;
|
||||
// import org.springframework.stereotype.Component;
|
||||
|
||||
// import javax.annotation.PostConstruct;
|
||||
|
||||
// /**
|
||||
// * 编码测试工具类
|
||||
// * 用于验证系统编码配置是否正确,解决中文乱码问题
|
||||
// */
|
||||
// @Component
|
||||
// public class EncodingTestUtil {
|
||||
|
||||
// private static final Logger logger = LoggerFactory.getLogger(EncodingTestUtil.class);
|
||||
|
||||
// /**
|
||||
// * 在Bean初始化时执行编码测试
|
||||
// * 验证日志系统是否能正确输出中文
|
||||
// */
|
||||
// @PostConstruct
|
||||
// public void testEncoding() {
|
||||
// // 输出系统编码信息
|
||||
// logger.info("===== 系统编码测试开始 =====");
|
||||
// logger.info("默认字符编码: {}", java.nio.charset.Charset.defaultCharset());
|
||||
// logger.info("file.encoding: {}", System.getProperty("file.encoding"));
|
||||
// logger.info("sun.stdout.encoding: {}", System.getProperty("sun.stdout.encoding"));
|
||||
// logger.info("sun.stderr.encoding: {}", System.getProperty("sun.stderr.encoding"));
|
||||
|
||||
// // 测试中文字符输出
|
||||
// logger.info("中文测试 - 这是一条测试日志,用于验证中文是否正常显示");
|
||||
// logger.warn("中文警告测试 - 这是一条警告日志,用于验证中文是否正常显示");
|
||||
// logger.error("中文错误测试 - 这是一条错误日志,用于验证中文是否正常显示");
|
||||
|
||||
// logger.info("===== 系统编码测试结束 =====");
|
||||
// }
|
||||
// }
|
||||
@@ -61,7 +61,11 @@ 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
|
||||
# 确保控制台输出使用UTF-8编码
|
||||
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
|
||||
# 日志编码配置 - 强制使用UTF-8
|
||||
logging.charset.file=UTF-8
|
||||
logging.charset.console=UTF-8
|
||||
# Actuator配置 - 生产环境建议限制暴露的端点
|
||||
management.endpoints.web.exposure.include=health,info,metrics,prometheus
|
||||
management.endpoint.health.show-details=when_authorized
|
||||
@@ -85,20 +89,41 @@ 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.web.locale=zh_CN
|
||||
#
|
||||
## 响应编码配置
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
spring.messages.encoding=UTF-8
|
||||
# 响应编码配置 - 确保所有响应使用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
|
||||
|
||||
# 配置控制台输出编码 - 通过日志系统配置确保中文显示正常
|
||||
# logging.pattern.console=%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40logger{39}}{cyan} %clr{:}{faint} %m%n%wEx
|
||||
|
||||
# 配置Maven启动JVM参数(需在启动时通过命令行指定或在pom.xml中配置)
|
||||
# 实际使用时请在启动命令中添加:-Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
|
||||
|
||||
# 更详细的日志配置 - 确保所有日志输出正确编码
|
||||
# logging.level.root=INFO
|
||||
# logging.level.org.springframework.web=DEBUG
|
||||
# logging.level.org.springframework.security=INFO
|
||||
# logging.level.com.qf.myafterprojecy=DEBUG
|
||||
|
||||
# 确保数据库连接编码正确
|
||||
spring.datasource.hikari.data-source-properties.useUnicode=true
|
||||
spring.datasource.hikari.data-source-properties.serverTimezone=Asia/Shanghai
|
||||
spring.datasource.hikari.data-source-properties.characterEncoding=utf-8
|
||||
|
||||
# 应用性能优化配置
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
spring.main.lazy-initialization=false
|
||||
|
||||
# API 文档配置
|
||||
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
|
||||
|
||||
Reference in New Issue
Block a user