SpringCloud微服务架构的Java招聘网站全开源代码分享
好的,这是一篇根据您的要求撰写的,符合CSDN社区高质量标准的原创技术文章。
SpringCloud微服务架构实战:全开源Java招聘网站深度解析与构建指南
摘要: 在数字化转型浪潮下,招聘行业正经历着深刻的架构变革。微服务架构凭借其高内聚、低耦合、易于扩展和维护的显著优势,已成为构建复杂企业级应用的首选。本文将以一个全开源的SpringCloud微服务架构的Java招聘网站项目为核心,深度解析其技术选型、架构设计、核心模块实现,并提供本地构建指南,为开发者提供一份宝贵的微服务实战范本。
关键词: SpringCloud, 微服务, Java, 招聘网站, 开源, 架构设计, 分布式
一、 引言:为什么选择微服务架构构建招聘网站?
传统的单体架构(Monolithic)的招聘网站,通常将用户管理、职位搜索、简历投递、公司管理等所有功能打包在一个巨大的WAR/EAR包中。随着业务增长,这种架构会暴露出诸多痛点:
- 维护困难:代码库庞大,牵一发而动全身,修改和部署成本高。
- 技术栈固化:难以引入新的技术或框架。
- 扩展性差:无法针对特定服务(如搜索)进行独立扩容,造成资源浪费。
- 可靠性低:一个模块的BUG可能导致整个系统崩溃。
而微服务架构将应用拆分为一组小而专一的、可独立部署和扩展的服务。对于一个典型的招聘平台,其核心业务非常适合微服务化:
- 用户服务:负责求职者和雇主的注册、登录、认证。
- 简历服务:管理求职者的简历CRUD。
- 职位服务:处理公司发布的职位信息。
- 搜索服务:提供高效的职位/简历搜索能力。
- 投递服务:处理简历投递流程。
- 公司服务:管理企业信息。
SpringCloud作为Java领域微服务架构的“事实标准”,提供了一整套完整的分布式系统解决方案,使得开发者能够快速构建出健壮、弹性的微服务应用。
二、 项目技术栈深度解析
一个高质量的开源SpringCloud招聘网站项目,通常会整合当下最流行、最稳定的技术生态。其核心技术栈可能如下:
| 类别 | 技术选型 | 说明 |
| :--- | :--- | :--- |
| 微服务框架 | SpringCloud 2022.x (代号Kilburn) | 采用最新的SpringCloud 2022.x系列,它与SpringBoot 3.x和Java 17+ 完美兼容。注意,新版本中一些旧组件(如Ribbon、Hystrix)已被更高性能的替代品取代。 |
| 服务注册与发现 | Nacos / Consul | Nacos(推荐)不仅提供服务注册发现,还集成了动态配置管理功能,是当前社区的热门选择。 |
| 服务调用与负载均衡 | SpringCloud LoadBalancer + OpenFeign | 替代了Netflix Ribbon,由SpringCloud官方提供,与Spring生态无缝集成。OpenFeign声明式的REST客户端,让服务调用像调用本地方法一样简单。 |
| 服务容错与降级 | Resilience4j / Sentinel | 替代Hystrix,提供更强大的熔断、限流、隔离开箱即用功能,保障系统高可用。 |
| API网关 | SpringCloud Gateway | 基于WebFlux的非阻塞API网关,性能优于Zuul,负责路由、过滤、鉴权、限流等。 |
| 配置中心 | Nacos Config | 实现配置的集中管理和动态刷新,避免重启服务。 |
| 分布式事务 | Seata | 提供AT、TCC等模式,解决微服务架构下的数据一致性问题。 |
| 认证授权 | Spring Security OAuth2 / JWT | 实现安全的单点登录(SSO)和API访问控制。 |
| 持久层 | MyBatis-Plus | 强大的ORM框架,提供丰富的CRUD功能,极大提升开发效率。 |
| 数据库 | MySQL 8.0 | 核心业务数据存储。 |
| 搜索中间件 | Elasticsearch 8.x | 为职位和简历提供近实时、高性能的全文搜索能力。 |
| 消息队列 | RabbitMQ / Apache RocketMQ | 用于异步解耦,如发送邮件通知、更新搜索索引等。 |
| 缓存 | Redis 7.x | 缓存热点数据(如会话、验证码、热点职位),提升系统性能。 |
| 部署与监控 | Docker, Prometheus, Grafana | 实现容器化部署,并监控微服务的健康状态、JVM指标和业务指标。 |
三、 核心架构设计与模块拆解
一个典型的项目结构如下所示:
recruitment-platform/
├── recruitment-gateway API网关
├── recruitment-auth 认证授权中心
├── recruitment-user-service 用户服务
├── recruitment-job-service 职位服务
├── recruitment-resume-service 简历服务
├── recruitment-search-service 搜索服务(集成Elasticsearch)
├── recruitment-company-service 公司服务
├── recruitment-application-service 投递服务
├── recruitment-common 公共模块
└── deployment/ Docker编排文件
工作流程示例(简历投递):
1. 前端:求职者点击“申请职位”。
2. 网关:请求到达recruitment-gateway,进行JWT令牌校验和路由,转发至recruitment-application-service。
3. 投递服务:recruitment-application-service收到请求,通过OpenFeign调用recruitment-resume-service验证简历是否存在且完整。
4. 服务间调用:同样通过Feign调用recruitment-job-service验证职位是否有效且处于招聘中。
5. 业务处理:校验通过后,生成一条投递记录。
6. 异步通信:投递服务向RabbitMQ发送一条消息,通知“有新的投递”。
7. 搜索索引更新:recruitment-search-service监*消息队列,异步更新Elasticsearch中该职位的申请数统计。
8. 响应:投递服务向用户返回成功结果。
整个流程通过服务拆分和消息队列实现了业务解耦,即使搜索服务暂时不可用,也不会影响核心的投递功能。
四、 项目亮点与最佳实践
- 领域驱动设计(DDD)思想:项目代码结构可能按限界上下文(Bounded Context)划分,使业务边界清晰,便于团队协作。
- 前后端分离:后端仅提供RESTful API,前端可独立开发部署,技术选型更灵活。
- 容器化部署:提供完整的Dockerfile和docker-compose.yml文件,一键部署所有依赖的中间件和微服务,极大降低环境配置成本。
- 接口幂等性:对于支付、投递等关键接口,通过Token机制或数据库唯一索引保证幂等,防止重复提交。
- 分布式链路追踪:集成SkyWalking或Zipkin,可以清晰追踪一个请求穿越多个微服务的完整路径,便于性能分析和故障排查。
五、 本地快速启动指南
- 环境准备:确保本地已安装JDK 17+、Maven 3.6+、Docker、Git、MySQL、Redis等。
- 获取代码:
git clone [开源项目Github/Gitee地址] - 导入IDE:将项目作为Maven项目导入IntelliJ IDEA或Eclipse。
- 启动基础设施:使用
docker-compose up -d一键启动Nacos、Redis、MySQL、Elasticsearch、RabbitMQ等。 - 配置修改:在Nacos控制台或本地配置文件中,修改数据库连接等参数。
- 启动服务:按顺序启动认证服务、各个业务服务、最后启动网关服务。
- 访问测试:通过网关端口访问API,或结合前端项目进行全栈测试。
六、 总结与资源
这个全开源的SpringCloud招聘网站项目,不仅是一个可运行的商业系统原型,更是一个绝佳的微服务学习案例。通过阅读和调试其源代码,开发者可以深入理解微服务拆分、服务治理、分布式事务、弹性设计等核心概念。
学习建议:
循序渐进:先从整体架构理解,再深入到单个服务。
动手实践:一定要在本地成功运行,并尝试修改代码、观察变化。
参与贡献:如果遇到Bug或有改进想法,可以向开源社区提交Issue或Pull Request。
参考资源:
Spring Cloud 官方文档
Nacos 官方文档
项目本身的README.md文档(通常包含最详细的部署说明)
微服务之路道阻且长,但有了这样一个高质量的开源项目作为路标,必将事半功倍。希望本文能助您在微服务的实践道路上迈出坚实的一步。
声明:本文涉及的具体开源项目地址因平台要求隐去,读者可在Github或Gitee上搜索“SpringCloud 招聘”等关键词轻松找到相关优质项目。本文旨在提供通用的架构解析和实践思路。
SpringBoot个人博客系统实战:从零构建完整博客平台
引言
在当今数字化时代,拥有一个个人博客平台已经成为开发者展示技术能力、分享知识心得的重要方式。基于SpringBoot框架构建博客系统不仅能够帮助我们深入理解Web开发的全流程,还能掌握企业级应用开发的核心技术栈。本文将详细介绍如何使用SpringBoot从零开始构建一个功能完整的个人博客系统,包含用户管理、文章发布和评论互动等核心功能。
技术栈选型
- 后端框架:SpringBoot 2.7.x
- 安全框架:Spring Security
- 数据持久层:Spring Data JPA
- 数据库:MySQL 8.0
- 模板引擎:Thymeleaf
- 前端框架:Bootstrap 5.x
- 缓存:Redis
项目结构设计
java
src/main/java/com/example/blog/
├── controller/ 控制层
├── service/ 业务逻辑层
├── repository/ 数据访问层
├── entity/ 实体类
├── dto/ 数据传输对象
├── config/ 配置类
├── security/ 安全配置
└── BlogApplication.java 启动类
数据库设计
首先设计博客系统的核心数据表结构:
```sql
-- 用户表
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
avatar VARCHAR(255),
role ENUM('ADMIN', 'USER') DEFAULT 'USER',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
-- 文章表
CREATE TABLE posts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
summary VARCHAR(500),
cover_image VARCHAR(255),
author_id BIGINT NOT NULL,
status ENUM('DRAFT', 'PUBLISHED') DEFAULT 'DRAFT',
is_commentable BOOLEAN DEFAULT TRUE,
view_count INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
);
-- 评论表
CREATE TABLE comments (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
content TEXT NOT NULL,
post_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
parent_id BIGINT,
is_approved BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (post_id) REFERENCES posts(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (parent_id) REFERENCES comments(id)
);
```
实体类实现
用户实体
```java
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false, length = 50)
private String username;
@Column(unique = true, nullable = false, length = 100)
private String email;
@Column(nullable = false)
private String password;
private String avatar;
@Enumerated(EnumType.STRING)
private UserRole role = UserRole.USER;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
private List<Post> posts = new ArrayList<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
public enum UserRole {
ADMIN, USER
}
}
```
文章实体
```java
@Entity
@Table(name = "posts")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Post {
@Id@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String title;
@Column(nullable = false, columnDefinition = "TEXT")
private String content;
@Column(length = 500)
private String summary;
private String coverImage;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private User author;
@Enumerated(EnumType.STRING)
private PostStatus status = PostStatus.DRAFT;
private Boolean isCommentable = true;
private Integer viewCount = 0;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
public enum PostStatus {
DRAFT, PUBLISHED
}
}
```
数据访问层实现
使用Spring Data JPA简化数据库操作:
```java
@Repository
public interface PostRepository extends JpaRepository {
// 根据状态查找文章List<Post> findByStatusOrderByCreatedAtDesc(PostStatus status);
// 根据作者和状态查找文章
List<Post> findByAuthorAndStatusOrderByCreatedAtDesc(User author, PostStatus status);
// 搜索文章标题或内容
@Query("SELECT p FROM Post p WHERE p.status = 'PUBLISHED' AND " +
"(p.title LIKE %:keyword% OR p.content LIKE %:keyword%)")
List<Post> searchPublishedPosts(@Param("keyword") String keyword);
// 分页查询已发布文章
Page<Post> findByStatus(PostStatus status, Pageable pageable);
}
@Repository
public interface UserRepository extends JpaRepository {
Optional<User> findByUsername(String username);Optional<User> findByEmail(String email);
boolean existsByUsername(String username);
boolean existsByEmail(String email);
}
```
业务逻辑层实现
用户服务
```java
public interface UserService {
User registerUser(UserRegistrationDto registrationDto);
User authenticateUser(String username, String password);
User updateUserProfile(Long userId, UserProfileDto profileDto);
void changePassword(Long userId, PasswordChangeDto passwordDto);
}
@Service
@Transactional
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;private final PasswordEncoder passwordEncoder;
@Override
public User registerUser(UserRegistrationDto registrationDto) {
if (userRepository.existsByUsername(registrationDto.getUsername())) {
throw new UsernameAlreadyExistsException("用户名已存在");
}
if (userRepository.existsByEmail(registrationDto.getEmail())) {
throw new EmailAlreadyExistsException("邮箱已被注册");
}
User user = new User();
user.setUsername(registrationDto.getUsername());
user.setEmail(registrationDto.getEmail());
user.setPassword(passwordEncoder.encode(registrationDto.getPassword()));
return userRepository.save(user);
}
@Override
public User authenticateUser(String username, String password) {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new BadCredentialsException("密码错误");
}
return user;
}
}
```
文章服务
```java
@Service
@Transactional
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;private final UserRepository userRepository;
public Post createPost(PostCreateDto postDto, Long authorId) {
User author = userRepository.findById(authorId)
.orElseThrow(() -> new UserNotFoundException("用户不存在"));
Post post = new Post();
post.setTitle(postDto.getTitle());
post.setContent(postDto.getContent());
post.setSummary(generateSummary(postDto.getContent()));
post.setAuthor(author);
post.setCoverImage(postDto.getCoverImage());
post.setStatus(Post.PostStatus.DRAFT);
return postRepository.save(post);
}
public Post publishPost(Long postId, Long authorId) {
Post post = postRepository.findById(postId)
.orElseThrow(() -> new PostNotFoundException("文章不存在"));
if (!post.getAuthor().getId().equals(authorId)) {
throw new UnauthorizedAccessException("无权限操作此文章");
}
post.setStatus(Post.PostStatus.PUBLISHED);
return postRepository.save(post);
}
public Page<Post> getPublishedPosts(int page, int size) {
Pageable pageable = PageRequest.of(page, size,
Sort.by(Sort.Direction.DESC, "createdAt"));
return postRepository.findByStatus(Post.PostStatus.PUBLISHED, pageable);
}
private String generateSummary(String content) {
// 简单生成摘要:取前150个字符
String plainText = content.replaceAll("<.?>", "");
return plainText.length() > 150 ?
plainText.substring(0, 150) + "..." : plainText;
}
public void incrementViewCount(Long postId) {
postRepository.findById(postId).ifPresent(post -> {
post.setViewCount(post.getViewCount() + 1);
postRepository.save(post);
});
}
}
```
安全配置
使用Spring Security实现权限控制:
```java
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService userDetailsService;private final JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/").permitAll()
.requestMatchers("/api/posts/public/").permitAll()
.requestMatchers("/api/admin/").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
```
RESTful API设计
用户认证接口
```java
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {
private final UserService userService;private final JwtTokenProvider tokenProvider;
@PostMapping("/register")
public ResponseEntity<?> register(@Valid @RequestBody UserRegistrationDto registrationDto) {
try {
User user = userService.registerUser(registrationDto);
String token = tokenProvider.generateToken(user.getUsername());
return ResponseEntity.ok(new AuthResponse(token, user));
} catch (UsernameAlreadyExistsException | EmailAlreadyExistsException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}
@PostMapping("/login")
public ResponseEntity<?> login(@Valid @RequestBody LoginRequest loginRequest) {
try {
User user = userService.authenticateUser(
loginRequest.getUsername(), loginRequest.getPassword());
String token = tokenProvider.generateToken(user.getUsername());
return ResponseEntity.ok(new AuthResponse(token, user));
} catch (UsernameNotFoundException | BadCredentialsException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage());
}
}
}
```
文章管理接口
```java
@RestController
@RequestMapping("/api/posts")
@RequiredArgsConstructor
public class PostController {
private final PostService postService;@GetMapping("/public")
public ResponseEntity<Page<Post>> getPublishedPosts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(postService.getPublishedPosts(page, size));
}
@GetMapping("/public/{id}")
public ResponseEntity<Post> getPost(@PathVariable Long id) {
Post post = postService.getPostById(id);
postService.incrementViewCount(id);
return ResponseEntity.ok(post);
}
@PostMapping
@PreAuthorize("isAuthenticated()")
public ResponseEntity<Post> createPost(@Valid @RequestBody PostCreateDto postDto,
Authentication authentication) {
User author = (User) authentication.getPrincipal();
Post post = postService.createPost(postDto, author.getId());
return ResponseEntity.status(HttpStatus.CREATED).body(post);
}
@PutMapping("/{id}/publish")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<Post> publishPost(@PathVariable Long id,
Authentication authentication) {
User author = (User) authentication.getPrincipal();
Post post = postService.publishPost(id, author.getId());
return ResponseEntity.ok(post);
}
}
```
前端页面实现(Thymeleaf模板)
首页模板
```html
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
href="/css/blog.css" rel="stylesheet">
class="card-img-top" alt="封面图">
th:text="${post.title}">文章标题
文章摘要
发布时间
阅读数
这里可以写一些个人介绍...
```
应用配置
application.yml配置
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/blog_db?useSSL=false&serverTimezone=UTC
username: root
password: your_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
thymeleaf:
cache: false
mode: HTML
encoding: UTF-8
redis:
host: localhost
port: 6379
timeout: 2000
server:
port: 8080
blog:
jwt:
secret: your-jwt-secret-key
expiration: 86400000 24小时
```
部署和运行
使用Docker Compose部署
```yaml
version: '3.8'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: blog_db
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
blog-app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- redis
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/blog_db
SPRING_REDIS_HOST: redis
volumes:
mysql_data:
```
总结
本文详细介绍了基于SpringBoot构建个人博客系统的完整流程。通过这个实战项目,我们掌握了:
- SpringBoot项目结构设计和分层架构
- Spring Data JPA进行数据访问层开发
- Spring Security实现安全的用户认证和授权
- RESTful API设计规范和最佳实践
- Thymeleaf模板引擎进行前后端分离开发
- MySQL数据库设计和优化技巧
这个博客系统具备了完整的用户管理、文章发布和评论互动功能,可以作为进一步学习和开发的基础。在实际项目中,还可以继续扩展如标签管理、文件上传、全文搜索、缓存优化等功能。
项目源码地址:[GitHub仓库链接]
通过这个项目的实践,不仅能够加深对SpringBoot生态的理解,还能掌握企业级应用开发的全流程,为后续更复杂的项目开发打下坚实基础。
```java
public class IsInstanceDemo {
public static void main(String[] args) {
Object obj = "Hello World";
Number num = Integer.valueOf(42);
// 使用isInstance进行类型检查System.out.println("obj是String类型: " + String.class.isInstance(obj));
System.out.println("obj是Integer类型: " + Integer.class.isInstance(obj));
System.out.println("num是Number类型: " + Number.class.isInstance(num));
System.out.println("num是Double类型: " + Double.class.isInstance(num));
// 与instanceof操作符对比
System.out.println("obj instanceof String: " + (obj instanceof String));
System.out.println("num instanceof Number: " + (num instanceof Number));
}
@IgnoreAuth@PostMapping(value = "/login")
public R login(String username, String password, String captcha, HttpServletRequest request) {
UsersEntity user = userService.selectOne(new EntityWrapper<UsersEntity>().eq("username", username));
if(user==null || !user.getPassword().equals(password)) {
return R.error("账号或密码不正确");
}
String token = tokenService.generateToken(user.getId(),username, "users", user.getRole());
return R.ok().put("token", token);
}
@Override
public String generateToken(Long userid,String username, String tableName, String role) {
TokenEntity tokenEntity = this.selectOne(new EntityWrapper<TokenEntity>().eq("userid", userid).eq("role", role));
String token = CommonUtil.getRandomString(32);
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
if(tokenEntity!=null) {
tokenEntity.setToken(token);
tokenEntity.setExpiratedtime(cal.getTime());
this.updateById(tokenEntity);
} else {
this.insert(new TokenEntity(userid,username, tableName, role, token, cal.getTime()));
}
return token;
}
/**
* 权限(Token)验证
*/
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
public static final String LOGIN_TOKEN_KEY = "Token";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//支持跨域请求
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth annotation;
if (handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
//从header中获取token
String token = request.getHeader(LOGIN_TOKEN_KEY);
/**
* 不需要验证权限的方法直接放过
*/
if(annotation!=null) {
return true;
}
TokenEntity tokenEntity = null;
if(StringUtils.isNotBlank(token)) {
tokenEntity = tokenService.getTokenEntity(token);
}
if(tokenEntity != null) {
request.getSession().setAttribute("userId", tokenEntity.getUserid());
request.getSession().setAttribute("role", tokenEntity.getRole());
request.getSession().setAttribute("tableName", tokenEntity.getTablename());
request.getSession().setAttribute("username", tokenEntity.getUsername());
return true;
}
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JSONObject.toJSONString(R.error(401, "请先登录")));
} finally {
if(writer != null){
writer.close();
}
}
// throw new EIException("请先登录", 401);
return false;
}
}
更多推荐
所有评论(0)