feat(blog-backend): 后端代码开发中...
This commit is contained in:
@@ -21,16 +21,36 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
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-data-jpa'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
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-core'
|
||||||
implementation 'org.flywaydb:flyway-mysql'
|
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'
|
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.boot:spring-boot-starter-test'
|
||||||
testImplementation 'org.springframework.security:spring-security-test'
|
testImplementation 'org.springframework.security:spring-security-test'
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,13 @@ package cn.hamster3.application.blog;
|
|||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
|
||||||
|
|
||||||
|
@EnableJpaAuditing
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class HamsterBlogApplication {
|
public class HamsterBlogApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(HamsterBlogApplication.class, args);
|
SpringApplication.run(HamsterBlogApplication.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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<String> {
|
|
||||||
@Override
|
|
||||||
public Optional<String> getCurrentAuditor() {
|
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
User user = (User) authentication.getPrincipal();
|
|
||||||
return Optional.of(user.getUsername());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,11 +1,34 @@
|
|||||||
package cn.hamster3.application.blog.config;
|
package cn.hamster3.application.blog.config;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
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
|
@Configuration
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class WebConfig implements WebMvcConfigurer {
|
public class WebConfig {
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder getPasswordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuditorAware<String> 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());
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
@@ -1,22 +1,31 @@
|
|||||||
package cn.hamster3.application.blog.config.security;
|
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 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.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Collections;
|
@Component
|
||||||
|
|
||||||
public class UserDetailServiceImpl implements UserDetailsService {
|
public class UserDetailServiceImpl implements UserDetailsService {
|
||||||
@Resource
|
@Resource
|
||||||
private UserEntityRepository userRepo;
|
private UserRepository userRepo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
return userRepo.findByEmailOrUsername(username, username)
|
return userRepo.findByEmailOrNicknameAllIgnoreCase(username, username, UserEntity.class)
|
||||||
.map(o -> new User(o.getUsername(), o.getPassword(), Collections.emptyList()))
|
.map(user -> new User(
|
||||||
.orElseThrow(() -> new UsernameNotFoundException("user not found."));
|
user.getId().toString(),
|
||||||
|
user.getPassword(),
|
||||||
|
user.getPermissions()
|
||||||
|
.stream()
|
||||||
|
.map(permission -> new SimpleGrantedAuthority(permission.name()))
|
||||||
|
.toList()
|
||||||
|
)).orElseThrow(() -> new UsernameNotFoundException("user not found."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,5 @@
|
|||||||
|
package cn.hamster3.application.blog.constant;
|
||||||
|
|
||||||
|
public enum UserPermission {
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,16 @@
|
|||||||
|
package cn.hamster3.application.blog.constant;
|
||||||
|
|
||||||
|
public enum UserRole {
|
||||||
|
/**
|
||||||
|
* 游客
|
||||||
|
*/
|
||||||
|
GUEST,
|
||||||
|
/**
|
||||||
|
* 作者
|
||||||
|
*/
|
||||||
|
AUTHOR,
|
||||||
|
/**
|
||||||
|
* 管理员
|
||||||
|
*/
|
||||||
|
ADMINISTRATOR
|
||||||
|
}
|
@@ -7,6 +7,6 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
* 附件相关接口
|
* 附件相关接口
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/v1/attach")
|
@RequestMapping("/api/v1/attach")
|
||||||
public class AttachController {
|
public class AttachController {
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,21 @@
|
|||||||
package cn.hamster3.application.blog.controller;
|
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.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 博文相关接口
|
* 博文相关接口
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/v1/blog")
|
@RequestMapping("/api/v1/blog")
|
||||||
public class BlogController {
|
public class BlogController {
|
||||||
|
@GetMapping("/")
|
||||||
|
public ResponseVO<List<BlogEntity>> getBlogList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,21 +1,25 @@
|
|||||||
package cn.hamster3.application.blog.controller;
|
package cn.hamster3.application.blog.controller;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.service.IUserService;
|
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.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户相关接口
|
* 用户相关接口
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/v1/user")
|
@RequestMapping("/api/v1/user")
|
||||||
public class UserController {
|
public class UserController {
|
||||||
@Resource
|
@Resource
|
||||||
private IUserService userService;
|
private IUserService userService;
|
||||||
|
|
||||||
@PostMapping("/")
|
@PostMapping("/")
|
||||||
public Object registerUser() {
|
public ResponseVO<UserRegisterResponseVO> registerUser(@RequestBody @Valid UserRegisterRequireVO requireVO) {
|
||||||
return null;
|
return userService.registerUser(requireVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/")
|
@PutMapping("/")
|
||||||
@@ -24,7 +28,12 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public Object getUserInfo() {
|
public ResponseVO<Void> getAllUserInfo() {
|
||||||
|
return ResponseVO.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{userID}/")
|
||||||
|
public Object getUserInfo(@PathVariable String userID) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,5 +4,5 @@ import cn.hamster3.application.blog.entity.BlogEntity;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
public interface BlogEntityRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> {
|
public interface BlogRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> {
|
||||||
}
|
}
|
@@ -2,6 +2,7 @@ package cn.hamster3.application.blog.entity;
|
|||||||
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
import org.springframework.data.annotation.LastModifiedDate;
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
|
||||||
@@ -17,14 +18,15 @@ public class AttachEntity {
|
|||||||
@Column(name = "id", nullable = false)
|
@Column(name = "id", nullable = false)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@Setter
|
||||||
@JoinColumn(name = "uploader_id", nullable = false)
|
|
||||||
private UserEntity uploader;
|
|
||||||
|
|
||||||
@Lob
|
@Lob
|
||||||
@Basic(fetch = FetchType.LAZY)
|
@Basic(fetch = FetchType.LAZY)
|
||||||
@Column(name = "data")
|
@Column(name = "data")
|
||||||
private Blob data;
|
private byte[] data;
|
||||||
|
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "uploader_id", nullable = false)
|
||||||
|
private UserEntity uploader;
|
||||||
|
|
||||||
@CreatedDate
|
@CreatedDate
|
||||||
@Column(name = "create_time", nullable = false)
|
@Column(name = "create_time", nullable = false)
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
}
|
@@ -9,7 +9,7 @@ import org.springframework.data.annotation.CreatedBy;
|
|||||||
import org.springframework.data.annotation.CreatedDate;
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
import org.springframework.data.annotation.LastModifiedDate;
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 博文实体
|
* 博文实体
|
||||||
@@ -34,8 +34,10 @@ public class BlogEntity {
|
|||||||
@Column(name = "content")
|
@Column(name = "content")
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
@Setter
|
@OneToMany(mappedBy = "blogEntity", orphanRemoval = true)
|
||||||
@CreatedBy
|
@OrderBy("create_time DESC")
|
||||||
|
private List<BlogAttachEntity> attachEntities = new ArrayList<>();
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@JoinColumn(name = "uploader_id", nullable = false)
|
@JoinColumn(name = "uploader_id", nullable = false)
|
||||||
private UserEntity uploader;
|
private UserEntity uploader;
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
package cn.hamster3.application.blog.entity;
|
package cn.hamster3.application.blog.entity;
|
||||||
|
|
||||||
|
import cn.hamster3.application.blog.constant.UserPermission;
|
||||||
|
import cn.hamster3.application.blog.constant.UserRole;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -7,15 +9,15 @@ import lombok.ToString;
|
|||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
import org.springframework.data.annotation.LastModifiedDate;
|
import org.springframework.data.annotation.LastModifiedDate;
|
||||||
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "user_entity")
|
@Table(name = "user_entity")
|
||||||
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
public class UserEntity {
|
public class UserEntity {
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
@@ -27,16 +29,34 @@ public class UserEntity {
|
|||||||
private String email;
|
private String email;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Column(name = "username", nullable = false, unique = true, length = 32)
|
@Column(name = "nickname", nullable = false, unique = true, length = 32)
|
||||||
private String username;
|
private String nickname;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Column(name = "password", nullable = false, length = 32)
|
@Column(name = "password", nullable = false, length = 32)
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
@ElementCollection
|
||||||
|
@Column(name = "permission")
|
||||||
|
@CollectionTable(name = "user_entity_permissions", joinColumns = @JoinColumn(name = "user_id"))
|
||||||
|
private Set<UserPermission> permissions = new HashSet<>();
|
||||||
|
|
||||||
|
@Enumerated
|
||||||
|
@Column(name = "role", nullable = false)
|
||||||
|
private UserRole role;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "uploader", orphanRemoval = true)
|
||||||
|
@OrderBy("create_time DESC")
|
||||||
|
private List<AttachEntity> attachEntities = new ArrayList<>();
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "uploader", orphanRemoval = true)
|
||||||
|
@OrderBy("create_time DESC")
|
||||||
|
private List<BlogEntity> blogEntities = new ArrayList<>();
|
||||||
|
|
||||||
@CreatedDate
|
@CreatedDate
|
||||||
@Column(name = "create_time", nullable = false)
|
@Column(name = "create_time", nullable = false)
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
|
|
||||||
@LastModifiedDate
|
@LastModifiedDate
|
||||||
@Column(name = "update_time", nullable = false)
|
@Column(name = "update_time", nullable = false)
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
|
@@ -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);
|
||||||
|
}
|
@@ -1,4 +1,10 @@
|
|||||||
package cn.hamster3.application.blog.service;
|
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 {
|
public interface IUserService {
|
||||||
|
@NotNull ResponseVO<UserRegisterResponseVO> registerUser(@NotNull UserRegisterRequireVO requireVO);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
package cn.hamster3.application.blog.service.impl;
|
package cn.hamster3.application.blog.service.impl;
|
||||||
|
|
||||||
|
import cn.hamster3.application.blog.dao.BlogRepository;
|
||||||
import cn.hamster3.application.blog.service.IBlogService;
|
import cn.hamster3.application.blog.service.IBlogService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
public class BlogService implements IBlogService {
|
public class BlogService implements IBlogService {
|
||||||
|
@Resource
|
||||||
|
private BlogRepository blogRepo;
|
||||||
}
|
}
|
||||||
|
@@ -1,17 +1,42 @@
|
|||||||
package cn.hamster3.application.blog.service.impl;
|
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.service.IUserService;
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
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.annotation.Resource;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class UserService implements IUserService {
|
public class UserService implements IUserService {
|
||||||
@Resource
|
@Resource
|
||||||
private UserEntityRepository userRepo;
|
private PasswordEncoder passwordEncoder;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
@Resource
|
||||||
|
private UserRepository userRepo;
|
||||||
|
|
||||||
public ResponseVO<Void> registerUser() {
|
@Override
|
||||||
return null;
|
public @NotNull ResponseVO<UserRegisterResponseVO> 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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,19 +1,20 @@
|
|||||||
package cn.hamster3.application.blog.vo;
|
package cn.hamster3.application.blog.vo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
public class ResponseVO<T> {
|
public class ResponseVO<T> {
|
||||||
private int code;
|
@NotNull
|
||||||
|
private Integer code;
|
||||||
|
@NotNull
|
||||||
private String msg;
|
private String msg;
|
||||||
|
@Nullable
|
||||||
private T data;
|
private T data;
|
||||||
|
|
||||||
private ResponseVO(int code, String msg, T data) {
|
|
||||||
this.code = code;
|
|
||||||
this.msg = msg;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseVO<Void> success() {
|
public static ResponseVO<Void> success() {
|
||||||
return new ResponseVO<>(200, "", null);
|
return new ResponseVO<>(200, "", null);
|
||||||
}
|
}
|
||||||
@@ -30,7 +31,7 @@ public class ResponseVO<T> {
|
|||||||
return new ResponseVO<>(200, msg, data);
|
return new ResponseVO<>(200, msg, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResponseVO<Void> failed(String msg) {
|
public static <T> ResponseVO<T> failed(String msg) {
|
||||||
return new ResponseVO<>(403, msg, null);
|
return new ResponseVO<>(403, msg, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
}
|
@@ -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<UserPermission> permissions;
|
||||||
|
private Date createTime;
|
||||||
|
private Date updateTime;
|
||||||
|
}
|
@@ -1,27 +1,16 @@
|
|||||||
spring:
|
spring:
|
||||||
# 数据库连接配置
|
jpa:
|
||||||
datasource:
|
hibernate:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
# 自动创建 Entity 类的数据库表
|
||||||
url: jdbc:mysql://sql.hamster3.cn:3306/Test3?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
|
ddl-auto: update
|
||||||
username: Test
|
# open-in-view: true
|
||||||
password: Test123..
|
show-ddl: true
|
||||||
flyway:
|
# show-sql: true
|
||||||
# 是否启用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
|
|
||||||
autoconfigure:
|
autoconfigure:
|
||||||
exclude[0]: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
exclude:
|
||||||
exclude[1]: org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfigurationspring
|
# - org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
|
||||||
|
# - org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfigurationspring
|
||||||
|
|
||||||
|
springdoc:
|
||||||
|
swagger-ui:
|
||||||
|
enabled: true
|
||||||
|
3
blog-backend/src/main/resources/application-prod.yml
Normal file
3
blog-backend/src/main/resources/application-prod.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
springdoc:
|
||||||
|
swagger-ui:
|
||||||
|
enabled: false
|
@@ -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
|
|
||||||
|
|
@@ -1,4 +1,10 @@
|
|||||||
spring:
|
spring:
|
||||||
|
# 要使用的环境预设
|
||||||
|
# prod: 生产环境
|
||||||
|
# dev: 开发环境
|
||||||
|
# test: 测试环境
|
||||||
|
profiles:
|
||||||
|
active: prod
|
||||||
# 数据库连接配置
|
# 数据库连接配置
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
8
blog-backend/src/main/resources/banner-dev.txt
Normal file
8
blog-backend/src/main/resources/banner-dev.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
__ __ ___ .___ ___. _______.___________. _______ .______ .______ __ ______ _______ _______ ___________ ____
|
||||||
|
| | | | / \ | \/ | / | || ____|| _ \ | _ \ | | / __ \ / _____| | \ | ____\ \ / /
|
||||||
|
| |__| | / ^ \ | \ / | | (----`---| |----`| |__ | |_) | | |_) | | | | | | | | | __ ______ | .--. || |__ \ \/ /
|
||||||
|
| __ | / /_\ \ | |\/| | \ \ | | | __| | / | _ < | | | | | | | | |_ | |______| | | | || __| \ /
|
||||||
|
| | | | / _____ \ | | | | .----) | | | | |____ | |\ \----.| |_) | | `----.| `--' | | |__| | | '--' || |____ \ /
|
||||||
|
|__| |__| /__/ \__\ |__| |__| |_______/ |__| |_______|| _| `._____||______/ |_______| \______/ \______| |_______/ |_______| \__/
|
||||||
|
|
8
blog-backend/src/main/resources/banner.txt
Normal file
8
blog-backend/src/main/resources/banner.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
__ __ ___ .___ ___. _______.___________. _______ .______ .______ __ ______ _______
|
||||||
|
| | | | / \ | \/ | / | || ____|| _ \ | _ \ | | / __ \ / _____|
|
||||||
|
| |__| | / ^ \ | \ / | | (----`---| |----`| |__ | |_) | ______ | |_) | | | | | | | | | __
|
||||||
|
| __ | / /_\ \ | |\/| | \ \ | | | __| | / |______| | _ < | | | | | | | | |_ |
|
||||||
|
| | | | / _____ \ | | | | .----) | | | | |____ | |\ \----. | |_) | | `----.| `--' | | |__| |
|
||||||
|
|__| |__| /__/ \__\ |__| |__| |_______/ |__| |_______|| _| `._____| |______/ |_______| \______/ \______|
|
||||||
|
|
Reference in New Issue
Block a user