CREATE TABLE projects (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
budget DECIMAL(10, 2) NOT NULL,
current_stage VARCHAR(255) NOT NULL,
handler VARCHAR(255) NOT NULL,
status ENUM('pending', 'in_progress', 'archived') NOT NULL DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
@Entity
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private BigDecimal budget;
private String currentStage;
private String handler;
@Enumerated(EnumType.STRING)
private ProjectStatus status; // 使用枚举表示状态
// 省略getter和setter
}
public enum ProjectStatus {
PENDING, IN_PROGRESS, ARCHIVED
}
@RestController
@RequestMapping("/api/projects")
public class ProjectController {
@Autowired
private ProjectService projectService;
@GetMapping
public List<ProjectDTO> getAllProjects(@RequestParam(required = false) String status) {
// 根据状态筛选项目
return projectService.findAllByStatus(status);
}
@PutMapping("/{id}/status")
@PreAuthorize("hasRole('ADMIN')") // 使用Spring Security进行权限控制
public ResponseEntity<?> updateProjectStatus(@PathVariable Long id, @RequestBody ProjectStatusUpdateDTO statusUpdate) {
// 更新项目状态
projectService.updateStatus(id, statusUpdate.getStatus());
return ResponseEntity.ok().build();
}
// 其他方法...
}
<template>
<div>
<select v-model="selectedStatus" @change="fetchProjects">
<option value="">所有</option>
<option value="pending">待处理</option>
<option value="in_progress">流转中</option>
<option value="archived">归档</option>
</select>
<ul>
<li v-for="project in projects" :key="project.id">{{ project.name }} - {{ project.status }}</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
selectedStatus: '',
projects: []
};
},
methods: {
fetchProjects() {
// 调用API获取项目列表,这里使用axios或fetch
axios.get(`/api/projects?status=${this.selectedStatus}`).then(response => {
this.projects = response.data;
});
}
},
created() {
this.fetchProjects();
}
};
</script>
<template>
<div>
<h1>{{ project.name }}</h1>
<!-- 其他项目详情展示 -->
<!-- 状态更新按钮,仅管理员可见 -->
<button v-if="isAdmin" @click="updateProjectStatus">更新状态</button>
<!-- 状态选择下拉菜单(可选,用于选择新状态) -->
<select v-model="newStatus" v-if="isAdmin">
<option value="pending">待处理</option>
<option value="in_progress">流转中</option>
<option value="archived">归档</option>
</select>
</div>
</template>
<script>
import axios from 'axios';
export default {
props: ['project'], // 假设这个组件接收一个project作为prop
data() {
return {
isAdmin: false, // 假设这里有一个方法来检查用户是否为管理员
newStatus: this.project.status // 初始新状态为当前状态
};
},
created() {
// 你可以在这里调用一个API来检查用户是否为管理员
// 例如:this.checkAdminStatus();
// 但为了简化,我们直接假设isAdmin的值
this.isAdmin = true; // 假设当前用户是管理员
},
methods: {
async updateProjectStatus() {
try {
// 发送PUT请求到后端以更新项目状态
await axios.put(`/api/projects/${this.project.id}/status`, {
status: this.newStatus
});
// 更新本地项目状态(可选,取决于是否需要立即反馈)
this.project.status = this.newStatus;
// 显示成功消息或进行其他操作
alert('项目状态已更新!');
} catch (error) {
// 处理错误,例如显示错误消息
console.error('更新项目状态失败:', error);
alert('更新项目状态时发生错误!');
}
},
// checkAdminStatus() {
// // 这里实现检查用户是否为管理员的逻辑
// // 可以通过调用后端API或使用Vuex/localStorage等方式
// }
}
};
</script>
在Spring Security中,UserDetailsService
是一个接口,用于加载用户特定的数据。当用户尝试访问受保护的资源时,Spring Security会调用实现了这个接口的类的 loadUserByUsername
方法来获取用户的详细信息,包括他们的权限和角色。这个方法返回的是一个 UserDetails
对象,它包含了用户的权限信息。
怎么实现UserDetailsService接口来定义哪些用户具有ADMIN角色。
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.Service;
import java.util.Arrays;
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 这里应该是一个从数据库或其他数据源获取用户信息的调用
// 但为了演示,我们直接在这里硬编码一些用户信息
// 假设有两个用户:user(普通用户)和admin(管理员)
if ("user".equals(username)) {
// 返回一个具有USER角色的UserDetails对象
return User.withUsername("user")
.password("{noop}password") // 注意:在生产环境中,密码应该是加密的
.roles("USER") // 分配角色
.build();
} else if ("admin".equals(username)) {
// 返回一个具有ADMIN角色的UserDetails对象
return User.withUsername("admin")
.password("{noop}admin") // 注意:在生产环境中,密码应该是加密的
.roles("ADMIN") // 分配角色
.build();
}
// 如果找不到用户,则抛出UsernameNotFoundException
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
//配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
// 其他配置...
}