好的,这是一篇根据您的要求撰写的,符合CSDN社区高质量标准的原创技术文章。


SpringCloud微服务架构实战:全开源Java招聘网站深度解析与构建指南

摘要: 在数字化转型浪潮下,招聘行业正经历着深刻的架构变革。微服务架构凭借其高内聚、低耦合、易于扩展和维护的显著优势,已成为构建复杂企业级应用的首选。本文将以一个全开源的SpringCloud微服务架构的Java招聘网站项目为核心,深度解析其技术选型、架构设计、核心模块实现,并提供本地构建指南,为开发者提供一份宝贵的微服务实战范本。

关键词: SpringCloud, 微服务, Java, 招聘网站, 开源, 架构设计, 分布式


一、 引言:为什么选择微服务架构构建招聘网站?

传统的单体架构(Monolithic)的招聘网站,通常将用户管理、职位搜索、简历投递、公司管理等所有功能打包在一个巨大的WAR/EAR包中。随着业务增长,这种架构会暴露出诸多痛点:

  • 维护困难:代码库庞大,牵一发而动全身,修改和部署成本高。
  • 技术栈固化:难以引入新的技术或框架。
  • 扩展性差:无法针对特定服务(如搜索)进行独立扩容,造成资源浪费。
  • 可靠性低:一个模块的BUG可能导致整个系统崩溃。

而微服务架构将应用拆分为一组小而专一的、可独立部署和扩展的服务。对于一个典型的招聘平台,其核心业务非常适合微服务化:

  • 用户服务:负责求职者和雇主的注册、登录、认证。
  • 简历服务:管理求职者的简历CRUD。
  • 职位服务:处理公司发布的职位信息。
  • 搜索服务:提供高效的职位/简历搜索能力。
  • 投递服务:处理简历投递流程。
  • 公司服务:管理企业信息。

SpringCloud作为Java领域微服务架构的“事实标准”,提供了一整套完整的分布式系统解决方案,使得开发者能够快速构建出健壮、弹性的微服务应用。

二、 项目技术栈深度解析

一个高质量的开源SpringCloud招聘网站项目,通常会整合当下最流行、最稳定的技术生态。其核心技术栈可能如下:

| 类别 | 技术选型 | 说明 |

| :--- | :--- | :--- |

| 微服务框架 | SpringCloud 2022.x (代号Kilburn) | 采用最新的SpringCloud 2022.x系列,它与SpringBoot 3.xJava 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. 响应:投递服务向用户返回成功结果。

整个流程通过服务拆分和消息队列实现了业务解耦,即使搜索服务暂时不可用,也不会影响核心的投递功能。

四、 项目亮点与最佳实践

  1. 领域驱动设计(DDD)思想:项目代码结构可能按限界上下文(Bounded Context)划分,使业务边界清晰,便于团队协作。
  2. 前后端分离:后端仅提供RESTful API,前端可独立开发部署,技术选型更灵活。
  3. 容器化部署:提供完整的Dockerfile和docker-compose.yml文件,一键部署所有依赖的中间件和微服务,极大降低环境配置成本。
  4. 接口幂等性:对于支付、投递等关键接口,通过Token机制或数据库唯一索引保证幂等,防止重复提交。
  5. 分布式链路追踪:集成SkyWalkingZipkin,可以清晰追踪一个请求穿越多个微服务的完整路径,便于性能分析和故障排查。

五、 本地快速启动指南

  1. 环境准备:确保本地已安装JDK 17+、Maven 3.6+、Docker、Git、MySQL、Redis等。
  2. 获取代码git clone [开源项目Github/Gitee地址]
  3. 导入IDE:将项目作为Maven项目导入IntelliJ IDEA或Eclipse。
  4. 启动基础设施:使用docker-compose up -d一键启动Nacos、Redis、MySQL、Elasticsearch、RabbitMQ等。
  5. 配置修改:在Nacos控制台或本地配置文件中,修改数据库连接等参数。
  6. 启动服务:按顺序启动认证服务、各个业务服务、最后启动网关服务。
  7. 访问测试:通过网关端口访问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构建个人博客系统的完整流程。通过这个实战项目,我们掌握了:

  1. SpringBoot项目结构设计和分层架构
  2. Spring Data JPA进行数据访问层开发
  3. Spring Security实现安全的用户认证和授权
  4. RESTful API设计规范和最佳实践
  5. Thymeleaf模板引擎进行前后端分离开发
  6. 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;

}

}

更多推荐