基于Spring boot和Vue3的博客平台:系统通知、评论回复通知、专栏更新通知、用户角色与权限管理模块

news/2024/10/31 5:24:15/

目录

一、系统通知、评论回复通知、专栏更新通知

1.前端通知展示

2.后端通知实现

3.发送评论回复通知

4.发送专栏更新通知

二、实时通知与邮件通知

1.实时通知

三、用户角色与权限管理

1.角色与权限数据模型

2.分配角色与权限

3.基于角色的访问控制


在这篇博客中,我们将介绍如何为我们的博客平台实现通知功能。这将包括系统通知、评论回复通知以及专栏更新通知。

一、系统通知、评论回复通知、专栏更新通知

1.前端通知展示

在前端项目中,创建一个新的 Notification.vue 组件。在这个组件中,我们将展示用户收到的所有通知。

<template><div class="notifications"><h3>Notifications</h3><ul><li v-for="notification in notifications" :key="notification.id">{{ notification.content }}</li></ul></div>
</template><script>
export default {data() {return {notifications: [],};},async mounted() {await this.fetchNotifications();},methods: {async fetchNotifications() {// ... 获取通知的逻辑 ...},},
};
</script>

2.后端通知实现

在后端项目中,创建一个新的 Notification 实体类,用于存储通知。

@Entity
public class Notification {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@ManyToOneprivate User recipient;private String content;// ... getter 和 setter ...
}

接下来,在 NotificationRepository 中,添加一个方法,根据接收者查找通知。

 
public interface NotificationRepository extends JpaRepository<Notification, Long> {List<Notification> findByRecipientId(Long recipientId);
}

接下来,在 NotificationController 中添加获取用户通知的接口。

 
@RestController
@RequestMapping("/api/notifications")
public class NotificationController {@Autowiredprivate NotificationRepository notificationRepository;@GetMappingpublic ResponseEntity<?> getUserNotifications(Principal principal) {// ... 获取用户通知的逻辑 ...}
}

3.发送评论回复通知

在评论回复功能中,当用户回复了某篇文章或其他评论时,我们可以为被回复的用户发送一条通知。在 CommentControllersubmitArticleComment 方法中,添加发送通知的逻辑。

@PostMapping
public ResponseEntity<?> submitArticleComment(@PathVariable Long articleId, @RequestBody CommentDto commentDto, Principal principal) {// ... 提交评论的逻辑 ...// 发送通知Notification notification = new Notification();notification.setRecipient(/* 被回复的用户 */);notification.setContent(/* 通知内容 */);notificationRepository.save(notification);return ResponseEntity.ok(comment);
}

4.发送专栏更新通知

当专栏作者发布新文章时,我们可以为订阅了该专栏的用户发送一条通知。首先,我们需要在 SubscriptionRepository 中添加一个方法,根据专栏 ID 查找订阅者。

public interface SubscriptionRepository extends JpaRepository<Subscription, Long> {List<Subscription> findByColumnId(Long columnId);
}

接下来,在 ArticleController 的 createArticle 方法中,添加发送通知的逻辑。

 
@PostMapping
public ResponseEntity<?> createArticle(@RequestBody ArticleDto articleDto, Principal principal) {// ... 创建文章的逻辑 ...// 获取专栏订阅者List<Subscription> subscriptions = subscriptionRepository.findByColumnId(article.getColumn().getId());// 遍历订阅者,发送通知for (Subscription subscription : subscriptions) {Notification notification = new Notification();notification.setRecipient(subscription.getUser());notification.setContent("专栏 [" + article.getColumn().getName() + "] 有新文章发布: " + article.getTitle());notificationRepository.save(notification);}return ResponseEntity.ok(article);
}

现在,每当专栏作者发布新文章时,系统将自动向订阅了该专栏的用户发送更新通知。这样,用户可以随时关注他们感兴趣的专栏,并获取最新文章的信息。

通过以上实现,我们已经为博客平台添加了系统通知、评论回复通知以及专栏更新通知功能。用户可以在通知页面查看他们收到的所有通知,这将极大地提高用户的参与度和互动体验。你可以根据需要进一步完善和扩展通知功能,例如提供邮件通知、实时通知等。

二、实时通知与邮件通知

在本节中,我们将为博客平台添加实时通知功能,以便用户在浏览网站时立即收到新通知。我们还将实现邮件通知功能,以便用户在收到关键通知时通过电子邮件获得提醒。

1.实时通知

为了实现实时通知,我们将使用 WebSocket 技术。首先,在后端项目中引入 Spring Boot WebSocket 依赖项。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

接下来,在 WebSocketConfig 类中配置 WebSocket。

 
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(notificationHandler(), "/api/ws/notifications").setAllowedOrigins("*");}@Beanpublic WebSocketHandler notificationHandler() {return new NotificationHandler();}
}

然后,创建一个 NotificationHandler 类,用于处理 WebSocket 通信。

 
public class NotificationHandler extends TextWebSocketHandler {// 存储 WebSocket 会话private final Map<Long, WebSocketSession> sessions = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {// ... 建立连接后的逻辑 ...}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// ... 处理接收到的消息 ...}// 发送实时通知public void sendNotification(Notification notification) {// ... 发送通知的逻辑 ...}
}

在前端项目中,使用 WebSocket API 连接到后端 WebSocket 服务器,并监听新通知。

 
// Notification.vue
export default {data() {return {// ...socket: null,};},mounted() {this.connectWebSocket();},methods: {// ...connectWebSocket() {this.socket = new WebSocket("ws://localhost:8080/api/ws/notifications");this.socket.addEventListener("message", this.handleNotification);},handleNotification(event) {const notification = JSON.parse(event.data);this.notifications.push(notification);},},
};

现在,每当用户收到新通知时,他们将立即在前端收到实时提醒。

2.邮件通知

为了实现邮件通知功能,我们将使用 JavaMailSender 发送电子邮件。首先,在后端项目中引入 Spring Boot Mail 依赖项。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId>
</dependency>

接下来,在 application.properties 文件中配置邮件发送相关属性。

spring.mail.host=smtp.example.com
spring.mail.port=587
spring.mail.username=your_email@example.com
spring.mail.password=your_email_password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true

创建一个 EmailService 类,用于发送邮件通知。

 
@Service
public class EmailService {@Autowiredprivate JavaMailSender javaMailSender;/*** 发送邮件通知* @param to 收件人* @param subject 邮件主题* @param content 邮件内容*/public void sendNotificationEmail(String to, String subject, String content) {SimpleMailMessage message = new SimpleMailMessage();message.setTo(to);message.setSubject(subject);message.setText(content);try {javaMailSender.send(message);} catch (MailException e) {// 如果发送邮件失败,记录错误信息System.err.println("发送邮件失败: " + e.getMessage());}}
}

现在,我们已经创建了一个 EmailService 类,用于发送邮件通知。你可以在需要发送邮件通知的地方调用此服务。例如,在发送评论回复通知时,可以同时发送一封邮件提醒被回复的用户:

@PostMapping
public ResponseEntity<?> submitArticleComment(@PathVariable Long articleId, @RequestBody CommentDto commentDto, Principal principal) {// ... 提交评论的逻辑 ...// 发送通知Notification notification = new Notification();notification.setRecipient(/* 被回复的用户 */);notification.setContent(/* 通知内容 */);notificationRepository.save(notification);// 发送邮件通知String recipientEmail = /* 被回复用户的邮箱地址 */;String emailSubject = "您在博客平台上收到了一条新评论";String emailContent = "您在文章《" + article.getTitle() + "》上收到了一条新评论:" + commentDto.getContent();emailService.sendNotificationEmail(recipientEmail, emailSubject, emailContent);return ResponseEntity.ok(comment);
}

通过以上实现,我们已经为博客平台添加了实时通知和邮件通知功能。用户在浏览网站时将实时收到新通知,并在关键通知发生时通过电子邮件获得提醒。这将极大地提高用户的参与度和互动体验。

三、用户角色与权限管理

为了实现不同类型的用户具有不同的权限,我们需要引入角色与权限管理。本节将介绍如何为用户分配角色,并根据角色分配权限。

1.角色与权限数据模型

首先,我们创建两个实体类:RolePermission,表示用户角色和权限。一个角色可以拥有多个权限,一个权限可以分配给多个角色。

@Entity
public class Role {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;@ManyToMany@JoinTable(name = "role_permission",joinColumns = @JoinColumn(name = "role_id"),inverseJoinColumns = @JoinColumn(name = "permission_id"))private Set<Permission> permissions;
}@Entity
public class Permission {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String name;@ManyToMany(mappedBy = "permissions")private Set<Role> roles;
}

接下来,更新 User 实体类,添加与 Role 的多对多关联。

 
@Entity
public class User {// ... 其他字段 ...@ManyToMany@JoinTable(name = "user_role",joinColumns = @JoinColumn(name = "user_id"),inverseJoinColumns = @JoinColumn(name = "role_id"))private Set<Role> roles;
}

2.分配角色与权限

创建一个 RoleRepository 和一个 PermissionRepository,用于操作角色和权限数据。

public interface RoleRepository extends JpaRepository<Role, Long> {
}public interface PermissionRepository extends JpaRepository<Permission, Long> {
}

接下来,创建一个初始化角色与权限的方法。例如,我们可以创建一个管理员角色,拥有所有权限,以及一个普通用户角色,只拥有部分权限。

 
@Service
public class InitService {@Autowiredprivate RoleRepository roleRepository;@Autowiredprivate PermissionRepository permissionRepository;public void initRolesAndPermissions() {// 创建权限Permission createArticle = new Permission("CREATE_ARTICLE");Permission editArticle = new Permission("EDIT_ARTICLE");Permission deleteArticle = new Permission("DELETE_ARTICLE");permissionRepository.saveAll(Arrays.asList(createArticle, editArticle, deleteArticle));// 创建普通用户角色Role userRole = new Role("USER");userRole.setPermissions(Collections.singleton(createArticle));roleRepository.save(userRole);// 创建管理员角色Role adminRole = new Role("ADMIN");adminRole.setPermissions(new HashSet<>(Arrays.asList(createArticle, editArticle, deleteArticle)));roleRepository.save(adminRole);}
}

3.基于角色的访问控制

为了实现基于角色的访问控制,我们需要在 SecurityConfig 类中配置权限控制规则。例如,只有管理员才能编辑和删除文章。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {// ... 其他配置 ...@Autowiredprivate CustomUserDetailsService customUserDetailsService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserDetailsService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http// ... 其他配置 ....authorizeRequests().antMatchers(HttpMethod.POST, "/api/articles").hasAnyRole("USER", "ADMIN").antMatchers(HttpMethod.PUT, "/api/articles/**").hasRole("ADMIN").antMatchers(HttpMethod.DELETE, "/api/articles/**").hasRole("ADMIN").antMatchers("/api/admin/**").hasRole("ADMIN").anyRequest().permitAll();}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Beanpublic AuthenticationEntryPoint authenticationEntryPoint() {return (request, response, authException) -> {response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");};}@Beanpublic AccessDeniedHandler accessDeniedHandler() {return (request, response, accessDeniedException) -> {response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");};}
}

在这个重写的基于角色的访问控制配置中,我们首先配置了用户创建文章的权限,允许具有 USERADMIN 角色的用户创建文章。接下来,我们为文章的编辑和删除操作设置了权限,仅允许具有 ADMIN 角色的用户进行这些操作。

我们还为 /api/admin/** 设置了访问权限,只允许具有 ADMIN 角色的用户访问该路径下的所有资源。

此外,我们添加了一个 AuthenticationEntryPoint 和一个 AccessDeniedHandler,用于自定义身份验证失败和访问被拒绝时的错误响应。

这样,我们已经实现了基于角色的访问控制,确保了不同类型的用户只能访问其被授权的资源。


http://www.ppmy.cn/news/42070.html

相关文章

卷积神经网络底层原理

1.卷积神经网络底层原理 声明&#xff1a;以下为《大话计算机》作者冬瓜哥课程视频截图&#xff0c;仅供学习 1.1卷积 一张图经过一种卷积核&#xff08;核函数&#xff09;滑动窗口进行卷积运算后得到一张特征图&#xff0c;这只是这种卷积核视角下看到的特征。所以我们需要多…

网络安全行业现在好混吗,工资水平怎么样?

一个离职转行员工的实话&#xff1a;网络安全是永远稀缺的&#xff0c;它的稀缺表现在你学不懂、学不够、学不通的知识与很高的技术壁垒的层面上。想混日子&#xff0c;这行最不缺的就是平庸之辈&#xff0c;想做好做强你要掂量自己有没有那个天赋&#xff01; 技术人才&#…

【Linux C/C++】关于结构体定义,typedef关键字的使用场景

typedef关键字修饰结构体声明的优劣 优势&#xff1a; 在C语言中&#xff0c;可以使用两种方式来定义结构体类型&#xff1a;使用struct关键字和使用typedef关键字。使用struct关键字定义结构体类型时&#xff0c;需要在定义时同时指定结构体的名称和成员变量&#xff0c;例如…

Compose (11/N) - 手势

一、点击 1.1 可点击 Modifier.clickable( ) 允许应用检测对该元素的点击。 Composable fun ClickableSample() {val count remember { mutableStateOf(0) }Text(text count.value.toString(),modifier Modifier.clickable { count.value 1 }) } 1.2 手势检测 Modifier.p…

【MATLAB图像处理实用案例详解(10)】——基于Kalman滤波的目标跟踪预测红色小球位置

目录一、Kalman滤波二、Kalman滤波源程序三、Kalman滤波预测红色小球位置程序实现一、Kalman滤波 Kalman 滤波算法是一个最优化自回归数据处理算法&#xff0c;对于很多问题的解決&#xff0c;它是最优、效率最高甚至是最有用的。Kalman 滤波的广泛应用己经超过30年&#xff0…

【C++】STL之stack、queue的使用和模拟实现+优先级队列(附仿函数)+容器适配器详解

之前的一段时间&#xff0c;我们共同学习了STL中一些容器&#xff0c;如string、vector和list等等。本章我们将步入新阶段的学习——容器适配器。本章将详解stack、queue的使用和模拟实现优先级队列&#xff08;附仿函数&#xff09;容器适配器等。 目录 &#xff08;一&…

【华为OD机试真题 Python】士兵过河

前言:本专栏将持续更新华为OD机试题目,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于OD机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:nansun0903@163.com;备注:CSDN。 题目描述 一支N个士兵的军…

大龄程序员不爱占便宜而得不到重用,职场新人早点get到

年龄大的人他不愿意占便宜 老板他也占不了年龄大的便宜 所以就不用你 你听明白了吗 跟大家就是聊一聊就是 关心的就是我们现在关心的是什么呢 就是咱们现在不是年轻人 包括刚毕业的 就聊一下我们的感受 聊聊我们感受 就说你很多就是说大家工作 大家觉得工作不就投投简历吗 人家…