From 6443f63f6e6e283edd8e73f82ebba49fd2a52c03 Mon Sep 17 00:00:00 2001 From: MiniDay <372403923@qq.com> Date: Sat, 4 Mar 2023 22:50:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(blog-backend):=20=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=BC=80=E5=8F=91=E4=B8=AD...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog-backend/build.gradle | 28 +++++++++++-- .../blog/HamsterBlogApplication.java | 5 ++- .../blog/config/UserIDAuditorAware.java | 22 ----------- .../application/blog/config/WebConfig.java | 27 ++++++++++++- .../security/DevSecurityConfiguration.java | 26 +++++++++++++ .../security/SecurityConfiguration.java | 32 +++++++++++++++ .../security/UserDetailServiceImpl.java | 23 +++++++---- .../blog/constant/UserPermission.java | 5 +++ .../application/blog/constant/UserRole.java | 16 ++++++++ .../blog/controller/AttachController.java | 2 +- .../blog/controller/BlogController.java | 11 +++++- .../blog/controller/UserController.java | 17 ++++++-- ...ityRepository.java => BlogRepository.java} | 2 +- .../application/blog/entity/AttachEntity.java | 12 +++--- .../blog/entity/BlogAttachEntity.java | 39 +++++++++++++++++++ .../application/blog/entity/BlogEntity.java | 8 ++-- .../application/blog/entity/UserEntity.java | 30 +++++++++++--- .../application/blog/mapper/UserMapper.java | 18 +++++++++ .../blog/service/IUserService.java | 6 +++ .../blog/service/impl/BlogService.java | 6 +++ .../blog/service/impl/UserService.java | 33 ++++++++++++++-- .../application/blog/vo/ResponseVO.java | 17 ++++---- .../blog/vo/user/UserRegisterRequireVO.java | 17 ++++++++ .../blog/vo/user/UserRegisterResponseVO.java | 20 ++++++++++ .../src/main/resources/application-dev.yml | 39 +++++++------------ .../src/main/resources/application-prod.yml | 3 ++ .../src/main/resources/application-test.yml | 25 ------------ .../src/main/resources/application.yml | 6 +++ .../src/main/resources/banner-dev.txt | 8 ++++ blog-backend/src/main/resources/banner.txt | 8 ++++ 30 files changed, 392 insertions(+), 119 deletions(-) delete mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/UserIDAuditorAware.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java rename blog-backend/src/main/java/cn/hamster3/application/blog/dao/{BlogEntityRepository.java => BlogRepository.java} (66%) create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogAttachEntity.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/mapper/UserMapper.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java create mode 100644 blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java create mode 100644 blog-backend/src/main/resources/application-prod.yml delete mode 100644 blog-backend/src/main/resources/application-test.yml create mode 100644 blog-backend/src/main/resources/banner-dev.txt create mode 100644 blog-backend/src/main/resources/banner.txt diff --git a/blog-backend/build.gradle b/blog-backend/build.gradle index 92bd0aa..f2dcb52 100644 --- a/blog-backend/build.gradle +++ b/blog-backend/build.gradle @@ -21,16 +21,36 @@ repositories { } dependencies { + // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-starter-webmvc-ui + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' + + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + implementation 'org.mapstruct:mapstruct:1.5.3.Final' + annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final' + + // https://mvnrepository.com/artifact/com.github.therapi/therapi-runtime-javadoc + implementation 'com.github.therapi:therapi-runtime-javadoc:0.15.0' + annotationProcessor 'com.github.therapi:therapi-runtime-javadoc:0.15.0' + + // https://mvnrepository.com/artifact/org.jetbrains/annotations + compileOnly 'org.jetbrains:annotations:24.0.0' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.session:spring-session-core' + implementation 'org.flywaydb:flyway-core' implementation 'org.flywaydb:flyway-mysql' - implementation 'org.springframework.session:spring-session-core' - compileOnly 'org.projectlombok:lombok' - developmentOnly 'org.springframework.boot:spring-boot-devtools' + runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' + + implementation 'org.springframework.boot:spring-boot-starter' + developmentOnly 'org.springframework.boot:spring-boot-devtools' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/HamsterBlogApplication.java b/blog-backend/src/main/java/cn/hamster3/application/blog/HamsterBlogApplication.java index 292e31c..a9eca34 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/HamsterBlogApplication.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/HamsterBlogApplication.java @@ -2,12 +2,13 @@ package cn.hamster3.application.blog; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class HamsterBlogApplication { - public static void main(String[] args) { SpringApplication.run(HamsterBlogApplication.class, args); } - } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/UserIDAuditorAware.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/UserIDAuditorAware.java deleted file mode 100644 index 12cb7ef..0000000 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/UserIDAuditorAware.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.hamster3.application.blog.config; - -import org.springframework.data.domain.AuditorAware; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.User; -import org.springframework.stereotype.Component; - -import java.util.Optional; - -@Component -public class UserIDAuditorAware implements AuditorAware { - @Override - public Optional getCurrentAuditor() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || !authentication.isAuthenticated()) { - return Optional.empty(); - } - User user = (User) authentication.getPrincipal(); - return Optional.of(user.getUsername()); - } -} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java index 10456cd..d152bcc 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/WebConfig.java @@ -1,11 +1,34 @@ package cn.hamster3.application.blog.config; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +import java.util.Optional; @Configuration @Slf4j -public class WebConfig implements WebMvcConfigurer { +public class WebConfig { + @Bean + public PasswordEncoder getPasswordEncoder() { + return new BCryptPasswordEncoder(5); + } + @Bean + public AuditorAware getUserIDAuditorAware() { + return () -> { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || !authentication.isAuthenticated()) { + return Optional.empty(); + } + User user = (User) authentication.getPrincipal(); + return Optional.of(user.getUsername()); + }; + } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java new file mode 100644 index 0000000..631e192 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/DevSecurityConfiguration.java @@ -0,0 +1,26 @@ +package cn.hamster3.application.blog.config.security; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Slf4j +@Configuration +@Profile("dev") +public class DevSecurityConfiguration { + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + log.info("development environment security settings enabled."); + return http.authorizeHttpRequests(request -> request + .anyRequest().permitAll() + ).csrf().disable() + .formLogin() + .and() + .httpBasic() + .and() + .build(); + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java new file mode 100644 index 0000000..bca77c7 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/SecurityConfiguration.java @@ -0,0 +1,32 @@ +package cn.hamster3.application.blog.config.security; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Slf4j +@Configuration +@Profile("prod") +public class SecurityConfiguration { + @Bean + SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + log.info("production environment security settings enabled."); + return http.authorizeHttpRequests(request -> request + .requestMatchers(HttpMethod.GET, "/", "/index", "/index.html").permitAll() + .requestMatchers(HttpMethod.GET, "/favicon.ico", "/assets/**").permitAll() + .requestMatchers(HttpMethod.GET, "/register", "/login").permitAll() + .requestMatchers(HttpMethod.GET, "/swagger-ui/**", "v3/api-docs/**").permitAll() + .requestMatchers(HttpMethod.POST, "/api/v1/user/").anonymous() + .anyRequest().authenticated() + ).csrf().disable() + .formLogin() + .and() + .httpBasic() + .and() + .build(); + } +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java index e768878..20bcbde 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/config/security/UserDetailServiceImpl.java @@ -1,22 +1,31 @@ package cn.hamster3.application.blog.config.security; -import cn.hamster3.application.blog.dao.UserEntityRepository; +import cn.hamster3.application.blog.dao.UserRepository; +import cn.hamster3.application.blog.entity.UserEntity; import jakarta.annotation.Resource; +import org.hibernate.Hibernate; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; 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; - +@Component public class UserDetailServiceImpl implements UserDetailsService { @Resource - private UserEntityRepository userRepo; + private UserRepository userRepo; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - return userRepo.findByEmailOrUsername(username, username) - .map(o -> new User(o.getUsername(), o.getPassword(), Collections.emptyList())) - .orElseThrow(() -> new UsernameNotFoundException("user not found.")); + return userRepo.findByEmailOrNicknameAllIgnoreCase(username, username, UserEntity.class) + .map(user -> new User( + user.getId().toString(), + user.getPassword(), + user.getPermissions() + .stream() + .map(permission -> new SimpleGrantedAuthority(permission.name())) + .toList() + )).orElseThrow(() -> new UsernameNotFoundException("user not found.")); } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java new file mode 100644 index 0000000..6423ea2 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserPermission.java @@ -0,0 +1,5 @@ +package cn.hamster3.application.blog.constant; + +public enum UserPermission { + +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java new file mode 100644 index 0000000..10d3ca9 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/constant/UserRole.java @@ -0,0 +1,16 @@ +package cn.hamster3.application.blog.constant; + +public enum UserRole { + /** + * 游客 + */ + GUEST, + /** + * 作者 + */ + AUTHOR, + /** + * 管理员 + */ + ADMINISTRATOR +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java index fb7d968..149b78c 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/AttachController.java @@ -7,6 +7,6 @@ import org.springframework.web.bind.annotation.RestController; * 附件相关接口 */ @RestController -@RequestMapping("/v1/attach") +@RequestMapping("/api/v1/attach") public class AttachController { } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/BlogController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/BlogController.java index e63e646..ec1ea96 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/BlogController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/BlogController.java @@ -1,12 +1,21 @@ package cn.hamster3.application.blog.controller; +import cn.hamster3.application.blog.entity.BlogEntity; +import cn.hamster3.application.blog.vo.ResponseVO; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** * 博文相关接口 */ @RestController -@RequestMapping("/v1/blog") +@RequestMapping("/api/v1/blog") public class BlogController { + @GetMapping("/") + public ResponseVO> getBlogList() { + return null; + } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java index 90ebce6..a204e60 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/controller/UserController.java @@ -1,21 +1,25 @@ package cn.hamster3.application.blog.controller; import cn.hamster3.application.blog.service.IUserService; +import cn.hamster3.application.blog.vo.ResponseVO; +import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; +import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; import jakarta.annotation.Resource; +import jakarta.validation.Valid; import org.springframework.web.bind.annotation.*; /** * 用户相关接口 */ @RestController -@RequestMapping("/v1/user") +@RequestMapping("/api/v1/user") public class UserController { @Resource private IUserService userService; @PostMapping("/") - public Object registerUser() { - return null; + public ResponseVO registerUser(@RequestBody @Valid UserRegisterRequireVO requireVO) { + return userService.registerUser(requireVO); } @PutMapping("/") @@ -24,7 +28,12 @@ public class UserController { } @GetMapping("/") - public Object getUserInfo() { + public ResponseVO getAllUserInfo() { + return ResponseVO.success(); + } + + @GetMapping("/{userID}/") + public Object getUserInfo(@PathVariable String userID) { return null; } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogEntityRepository.java b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogRepository.java similarity index 66% rename from blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogEntityRepository.java rename to blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogRepository.java index 6be395b..663492b 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogEntityRepository.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/dao/BlogRepository.java @@ -4,5 +4,5 @@ import cn.hamster3.application.blog.entity.BlogEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -public interface BlogEntityRepository extends JpaRepository, JpaSpecificationExecutor { +public interface BlogRepository extends JpaRepository, JpaSpecificationExecutor { } \ No newline at end of file diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/AttachEntity.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/AttachEntity.java index dd461ed..49e1895 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/AttachEntity.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/AttachEntity.java @@ -2,6 +2,7 @@ package cn.hamster3.application.blog.entity; import jakarta.persistence.*; import lombok.Getter; +import lombok.Setter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; @@ -17,14 +18,15 @@ public class AttachEntity { @Column(name = "id", nullable = false) private Long id; - @ManyToOne(optional = false) - @JoinColumn(name = "uploader_id", nullable = false) - private UserEntity uploader; - + @Setter @Lob @Basic(fetch = FetchType.LAZY) @Column(name = "data") - private Blob data; + private byte[] data; + + @ManyToOne(optional = false) + @JoinColumn(name = "uploader_id", nullable = false) + private UserEntity uploader; @CreatedDate @Column(name = "create_time", nullable = false) diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogAttachEntity.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogAttachEntity.java new file mode 100644 index 0000000..21b1f9a --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogAttachEntity.java @@ -0,0 +1,39 @@ +package cn.hamster3.application.blog.entity; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; + +import java.sql.Blob; +import java.util.Date; + +@Getter +@Setter +@Entity +@Table(name = "blog_attach_entity") +public class BlogAttachEntity { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id", nullable = false) + private Long id; + + @Lob + @Basic(fetch = FetchType.LAZY) + @Column(name = "data", nullable = false) + private byte[] data; + + @ManyToOne(optional = false) + @JoinColumn(name = "blog_entity_id", nullable = false) + private BlogEntity blogEntity; + + @CreatedDate + @Column(name = "create_time", nullable = false) + private Date createTime; + + @LastModifiedDate + @Column(name = "update_time", nullable = false) + private Date updateTime; + +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogEntity.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogEntity.java index d54d963..c62085f 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogEntity.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/BlogEntity.java @@ -9,7 +9,7 @@ import org.springframework.data.annotation.CreatedBy; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; -import java.util.Date; +import java.util.*; /** * 博文实体 @@ -34,8 +34,10 @@ public class BlogEntity { @Column(name = "content") private String content; - @Setter - @CreatedBy + @OneToMany(mappedBy = "blogEntity", orphanRemoval = true) + @OrderBy("create_time DESC") + private List attachEntities = new ArrayList<>(); + @ManyToOne(optional = false) @JoinColumn(name = "uploader_id", nullable = false) private UserEntity uploader; diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java index acdbf79..9420b45 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/entity/UserEntity.java @@ -1,5 +1,7 @@ package cn.hamster3.application.blog.entity; +import cn.hamster3.application.blog.constant.UserPermission; +import cn.hamster3.application.blog.constant.UserRole; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -7,15 +9,15 @@ import lombok.ToString; import org.hibernate.Hibernate; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.util.Date; -import java.util.Objects; -import java.util.UUID; +import java.util.*; @Getter @ToString @Entity @Table(name = "user_entity") +@EntityListeners(AuditingEntityListener.class) public class UserEntity { @Id @GeneratedValue(strategy = GenerationType.AUTO) @@ -27,16 +29,34 @@ public class UserEntity { private String email; @Setter - @Column(name = "username", nullable = false, unique = true, length = 32) - private String username; + @Column(name = "nickname", nullable = false, unique = true, length = 32) + private String nickname; @Setter @Column(name = "password", nullable = false, length = 32) private String password; + @ElementCollection + @Column(name = "permission") + @CollectionTable(name = "user_entity_permissions", joinColumns = @JoinColumn(name = "user_id")) + private Set permissions = new HashSet<>(); + + @Enumerated + @Column(name = "role", nullable = false) + private UserRole role; + + @OneToMany(mappedBy = "uploader", orphanRemoval = true) + @OrderBy("create_time DESC") + private List attachEntities = new ArrayList<>(); + + @OneToMany(mappedBy = "uploader", orphanRemoval = true) + @OrderBy("create_time DESC") + private List blogEntities = new ArrayList<>(); + @CreatedDate @Column(name = "create_time", nullable = false) private Date createTime; + @LastModifiedDate @Column(name = "update_time", nullable = false) private Date updateTime; diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/mapper/UserMapper.java b/blog-backend/src/main/java/cn/hamster3/application/blog/mapper/UserMapper.java new file mode 100644 index 0000000..2460baa --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/mapper/UserMapper.java @@ -0,0 +1,18 @@ +package cn.hamster3.application.blog.mapper; + +import cn.hamster3.application.blog.entity.UserEntity; +import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; +import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(componentModel = "spring") +public interface UserMapper { + + @Mapping(target = "permissions", ignore = true) + @Mapping(target = "attachEntities", ignore = true) + @Mapping(target = "blogEntities", ignore = true) + UserEntity voToEntity(UserRegisterRequireVO requireVO); + + UserRegisterResponseVO entityToVO(UserEntity requireVO); +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java index b6d0bd9..a5be873 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/IUserService.java @@ -1,4 +1,10 @@ package cn.hamster3.application.blog.service; +import cn.hamster3.application.blog.vo.ResponseVO; +import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; +import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; +import org.jetbrains.annotations.NotNull; + public interface IUserService { + @NotNull ResponseVO registerUser(@NotNull UserRegisterRequireVO requireVO); } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java index 89a74d0..f04e49f 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/BlogService.java @@ -1,6 +1,12 @@ package cn.hamster3.application.blog.service.impl; +import cn.hamster3.application.blog.dao.BlogRepository; import cn.hamster3.application.blog.service.IBlogService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +@Service public class BlogService implements IBlogService { + @Resource + private BlogRepository blogRepo; } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java index 92f9314..25856de 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/service/impl/UserService.java @@ -1,17 +1,42 @@ package cn.hamster3.application.blog.service.impl; -import cn.hamster3.application.blog.dao.UserEntityRepository; +import cn.hamster3.application.blog.dao.UserRepository; +import cn.hamster3.application.blog.entity.UserEntity; +import cn.hamster3.application.blog.mapper.UserMapper; import cn.hamster3.application.blog.service.IUserService; import cn.hamster3.application.blog.vo.ResponseVO; +import cn.hamster3.application.blog.vo.user.UserRegisterRequireVO; +import cn.hamster3.application.blog.vo.user.UserRegisterResponseVO; import jakarta.annotation.Resource; +import org.jetbrains.annotations.NotNull; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service public class UserService implements IUserService { @Resource - private UserEntityRepository userRepo; + private PasswordEncoder passwordEncoder; + @Resource + private UserMapper userMapper; + @Resource + private UserRepository userRepo; - public ResponseVO registerUser() { - return null; + @Override + public @NotNull ResponseVO registerUser(@NotNull UserRegisterRequireVO requireVO) { + UserEntity entity = userMapper.voToEntity(requireVO); + entity.setEmail(entity.getEmail().toLowerCase()); + + if (userRepo.existsByEmailIgnoreCase(entity.getEmail())) { + return ResponseVO.failed("已存在相同邮箱的账户!"); + } + + if (userRepo.existsByNicknameIgnoreCase(entity.getNickname())) { + return ResponseVO.failed("已存在相同的用户昵称!"); + } + + entity.setPassword(passwordEncoder.encode(entity.getPassword())); + UserEntity save = userRepo.save(entity); + + return ResponseVO.success("注册成功!", userMapper.entityToVO(save)); } } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java index 282907f..d985ac4 100644 --- a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/ResponseVO.java @@ -1,19 +1,20 @@ package cn.hamster3.application.blog.vo; +import lombok.AllArgsConstructor; import lombok.Data; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; @Data +@AllArgsConstructor public class ResponseVO { - private int code; + @NotNull + private Integer code; + @NotNull private String msg; + @Nullable private T data; - private ResponseVO(int code, String msg, T data) { - this.code = code; - this.msg = msg; - this.data = data; - } - public static ResponseVO success() { return new ResponseVO<>(200, "", null); } @@ -30,7 +31,7 @@ public class ResponseVO { return new ResponseVO<>(200, msg, data); } - public static ResponseVO failed(String msg) { + public static ResponseVO failed(String msg) { return new ResponseVO<>(403, msg, null); } diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java new file mode 100644 index 0000000..4db82de --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterRequireVO.java @@ -0,0 +1,17 @@ +package cn.hamster3.application.blog.vo.user; + +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UserRegisterRequireVO { + @Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!") + private String email; + @Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!") + private String nickname; + @Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!") + private String password; +} diff --git a/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java new file mode 100644 index 0000000..248dc68 --- /dev/null +++ b/blog-backend/src/main/java/cn/hamster3/application/blog/vo/user/UserRegisterResponseVO.java @@ -0,0 +1,20 @@ +package cn.hamster3.application.blog.vo.user; + +import cn.hamster3.application.blog.constant.UserPermission; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +public class UserRegisterResponseVO { + private UUID id; + private String email; + private String nickname; + private List permissions; + private Date createTime; + private Date updateTime; +} diff --git a/blog-backend/src/main/resources/application-dev.yml b/blog-backend/src/main/resources/application-dev.yml index 4615cd9..675beb7 100644 --- a/blog-backend/src/main/resources/application-dev.yml +++ b/blog-backend/src/main/resources/application-dev.yml @@ -1,27 +1,16 @@ spring: - # 数据库连接配置 - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://sql.hamster3.cn:3306/Test3?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 - username: Test - password: Test123.. - flyway: - # 是否启用flyway - enabled: true - # 编码格式,默认UTF-8 - encoding: UTF-8 - # 迁移sql脚本文件存放路径,默认db/migration - locations: classpath:db/migration - # 迁移sql脚本文件名称的前缀,默认V - sql-migration-prefix: V - # 迁移sql脚本文件名称的分隔符,默认2个下划线__ - sql-migration-separator: __ - # 迁移sql脚本文件名称的后缀 - sql-migration-suffixes: .sql - # 迁移时是否进行校验,默认true - validate-on-migrate: true - # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表 - baseline-on-migrate: true + jpa: + hibernate: + # 自动创建 Entity 类的数据库表 + ddl-auto: update +# open-in-view: true + show-ddl: true +# show-sql: true autoconfigure: - exclude[0]: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration - exclude[1]: org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfigurationspring + exclude: +# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration +# - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfigurationspring + +springdoc: + swagger-ui: + enabled: true diff --git a/blog-backend/src/main/resources/application-prod.yml b/blog-backend/src/main/resources/application-prod.yml new file mode 100644 index 0000000..eb77890 --- /dev/null +++ b/blog-backend/src/main/resources/application-prod.yml @@ -0,0 +1,3 @@ +springdoc: + swagger-ui: + enabled: false diff --git a/blog-backend/src/main/resources/application-test.yml b/blog-backend/src/main/resources/application-test.yml deleted file mode 100644 index 198bfee..0000000 --- a/blog-backend/src/main/resources/application-test.yml +++ /dev/null @@ -1,25 +0,0 @@ -spring: - # 数据库连接配置 - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://sql.hamster3.cn:3306/Test3?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 - username: Test - password: Test123.. - flyway: - # 是否启用flyway - enabled: true - # 编码格式,默认UTF-8 - encoding: UTF-8 - # 迁移sql脚本文件存放路径,默认db/migration - locations: classpath:db/migration - # 迁移sql脚本文件名称的前缀,默认V - sql-migration-prefix: V - # 迁移sql脚本文件名称的分隔符,默认2个下划线__ - sql-migration-separator: __ - # 迁移sql脚本文件名称的后缀 - sql-migration-suffixes: .sql - # 迁移时是否进行校验,默认true - validate-on-migrate: true - # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表 - baseline-on-migrate: true - diff --git a/blog-backend/src/main/resources/application.yml b/blog-backend/src/main/resources/application.yml index 65b3750..e1fc0d5 100644 --- a/blog-backend/src/main/resources/application.yml +++ b/blog-backend/src/main/resources/application.yml @@ -1,4 +1,10 @@ spring: + # 要使用的环境预设 + # prod: 生产环境 + # dev: 开发环境 + # test: 测试环境 + profiles: + active: prod # 数据库连接配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver diff --git a/blog-backend/src/main/resources/banner-dev.txt b/blog-backend/src/main/resources/banner-dev.txt new file mode 100644 index 0000000..76e0176 --- /dev/null +++ b/blog-backend/src/main/resources/banner-dev.txt @@ -0,0 +1,8 @@ + + __ __ ___ .___ ___. _______.___________. _______ .______ .______ __ ______ _______ _______ ___________ ____ +| | | | / \ | \/ | / | || ____|| _ \ | _ \ | | / __ \ / _____| | \ | ____\ \ / / +| |__| | / ^ \ | \ / | | (----`---| |----`| |__ | |_) | | |_) | | | | | | | | | __ ______ | .--. || |__ \ \/ / +| __ | / /_\ \ | |\/| | \ \ | | | __| | / | _ < | | | | | | | | |_ | |______| | | | || __| \ / +| | | | / _____ \ | | | | .----) | | | | |____ | |\ \----.| |_) | | `----.| `--' | | |__| | | '--' || |____ \ / +|__| |__| /__/ \__\ |__| |__| |_______/ |__| |_______|| _| `._____||______/ |_______| \______/ \______| |_______/ |_______| \__/ + diff --git a/blog-backend/src/main/resources/banner.txt b/blog-backend/src/main/resources/banner.txt new file mode 100644 index 0000000..0841257 --- /dev/null +++ b/blog-backend/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + + __ __ ___ .___ ___. _______.___________. _______ .______ .______ __ ______ _______ +| | | | / \ | \/ | / | || ____|| _ \ | _ \ | | / __ \ / _____| +| |__| | / ^ \ | \ / | | (----`---| |----`| |__ | |_) | ______ | |_) | | | | | | | | | __ +| __ | / /_\ \ | |\/| | \ \ | | | __| | / |______| | _ < | | | | | | | | |_ | +| | | | / _____ \ | | | | .----) | | | | |____ | |\ \----. | |_) | | `----.| `--' | | |__| | +|__| |__| /__/ \__\ |__| |__| |_______/ |__| |_______|| _| `._____| |______/ |_______| \______/ \______| +