亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Springboot企業級開發資料入門教程

標簽:
SpringBoot
概述

Spring Boot企业级开发资料介绍了如何使用Spring Boot进行企业级应用开发,包括快速搭建项目、数据库集成、异步任务处理和WebSocket等关键功能。文章还详细讲解了Spring Boot的安全配置和JWT技术的应用。通过丰富的示例代码和配置,帮助开发者更好地理解和使用Spring Boot的各项特性。

Spring Boot企业级开发资料入门教程
Spring Boot简介

Spring Boot是什么

Spring Boot 是一个微框架,它是 Spring 社区为简化新 Spring 应用程序的初始搭建和配置而提供的解决方案。它的设计目标是简化 Spring 应用的初始搭建及开发过程,使开发者能够快速编写单个模块的独立且生产级别的应用,无需编写大量配置代码。

Spring Boot的优势

  • 自动配置:Spring Boot 可以根据应用类型自动配置 Spring 框架。
  • 独立运行:支持打包可独立运行的应用,无需部署到应用服务器。
  • 嵌入式服务器:内置了 Tomcat、Jetty 或 Undertow 作为应用服务器。
  • 热部署:支持热部署,便于开发。
  • 开发工具集成:与大多数开发工具和构建工具(如 Maven 和 Gradle)无缝集成。
  • 监控与健康检查:内置监控和健康检查功能。
  • 无代码生成:不需要额外的 XML 配置,支持约定优于配置,减少样板代码。

第一个Spring Boot项目创建

使用 Spring Initializr(可以访问 https://start.spring.io/)快速创建一个 Spring Boot 项目。选择以下选项:

  • 项目类型:Maven Project
  • Java 版本:8 及以上
  • 语言:Java
  • 依赖:Spring Web
  • 包名:com.example.demo
  • 项目名:demo
  • 构建工具:Maven

生成的项目结构如下:

demo
│   .gitignore
│   pom.xml
│
└───src
    └───main
        ├───java
        │   └───com
        │       └───example
        │           └───demo
        │               │   DemoApplication.java
        │               └───controller
        │                       HelloController.java
        └───resources
            │   application.properties
            └───static

DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

HelloController.java

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, World!";
    }

}

src/main/resources/application.properties 文件中,可以添加一些基本配置:

server.port=8080

使用 Maven 打包并运行:

mvn clean package
java -jar target/demo-0.0.1-SNAPSHOT.jar
快速上手Spring Boot

Maven和Gradle项目搭建

Maven项目搭建

使用 Maven 作为构建工具,需要在项目根目录下创建 pom.xml 文件。示例内容如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Example project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.5.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Gradle项目搭建

使用 Gradle 作为构建工具,需要在项目根目录下创建 build.gradle 文件。示例内容如下:

plugins {
    id 'org.springframework.boot' version '2.5.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Spring Boot启动器与自动配置

Spring Boot 通过启动器 (Spring Boot Starter) 简化了依赖管理。启动器是包含一组预定义依赖项的特殊依赖项。例如,spring-boot-starter-web 包含创建 Spring Web 应用所需的所有依赖项。

自动配置 (Auto-configuration) 是 Spring Boot 的另一个关键特性,它允许框架自动配置您的 Spring 应用程序。例如,spring-boot-starter-web 包含了一个自动配置类,可以检测 DispatcherServlet 是否已经配置,并自动配置它。

MVC架构与Thymeleaf模板引擎

Spring Boot 支持 MVC 架构,其中 DispatcherServlet 作为前端控制器,负责接收 HTTP 请求并根据请求将控制传递给相应的处理器。处理器处理请求并返回视图,视图将模型数据传递给视图解析器以生成响应。

Thymeleaf 模板引擎

Thymeleaf 是一个 Java 模板引擎,用于生成 HTML、XML、JavaScript、CSS、任意文本文件等。它通过注解来注入变量,并与 Spring Boot 配合使用,可以简化前端视图的开发。

示例代码

src/main/resources/templates 目录下创建 index.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Spring Boot Thymeleaf Example</title>
</head>
<body>
    <h1 th:text="'Hello, ' + ${name} + '!'"></h1>
</body>
</html>

src/main/java/com/example/demo/controller 目录下创建 HomeController.java

package com.example.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

    @GetMapping("/")
    public String home(Model model) {
        model.addAttribute("name", "World");
        return "index";
    }

}
数据库集成

Spring Data JPA入门

Spring Data JPA 是 Spring Data 框架的一部分,简化了与 JPA(Java Persistence API)的集成。它允许开发者通过简单的方法名和类名来操作数据库。

示例代码

src/main/java/com/example/demo/entity 目录下创建 User.java

package com.example.demo.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;

    // Getters and Setters
}

src/main/java/com/example/demo/repository 目录下创建 UserRepository.java

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

src/main/java/com/example/demo/service 目录下创建 UserService.java

package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public List<User> getAllUsers() {
        return userRepository.findAll();
    }

    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public User updateUser(Long id, User user) {
        User existingUser = userRepository.findById(id).orElse(null);
        if (existingUser != null) {
            existingUser.setName(user.getName());
            existingUser.setEmail(user.getEmail());
            return userRepository.save(existingUser);
        }
        return null;
    }

    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

src/main/java/com/example/demo/controller 目录下创建 UserController.java

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

src/main/resources/application.properties 中添加数据库配置:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update

JDBC与MyBatis基本使用

Spring Boot 也支持 JDBC 和 MyBatis,但 JPA 和 MyBatis 更加流行。

JDBC 示例

src/main/java/com/example/demo/repository 目录下创建 JdbcUserRepository.java

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class JdbcUserRepository {

    private JdbcTemplate jdbcTemplate;

    public JdbcUserRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<User> getAllUsers() {
        return jdbcTemplate.query("SELECT * FROM users", new UserRowMapper());
    }

    public User getUserById(Long id) {
        return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", new UserRowMapper(), id);
    }

    public User createUser(User user) {
        jdbcTemplate.update("INSERT INTO users (name, email) VALUES (?, ?)", user.getName(), user.getEmail());
        return user;
    }

    public User updateUser(Long id, User user) {
        jdbcTemplate.update("UPDATE users SET name = ?, email = ? WHERE id = ?", user.getName(), user.getEmail(), id);
        return user;
    }

    public void deleteUser(Long id) {
        jdbcTemplate.update("DELETE FROM users WHERE id = ?", id);
    }

    private static class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            user.setEmail(rs.getString("email"));
            return user;
        }
    }
}

MyBatis 示例

需要添加 mybatis-spring-boot-starter 依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

src/main/resources/mapper/UserMapper.xml 中定义 SQL 语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.repository.UserRepository">
    <select id="getAllUsers" resultType="com.example.demo.entity.User">
        SELECT * FROM users
    </select>

    <select id="getUserById" resultType="com.example.demo.entity.User">
        SELECT * FROM users WHERE id = #{id}
    </select>

    <insert id="createUser">
        INSERT INTO users (name, email) VALUES (#{name}, #{email})
    </insert>

    <update id="updateUser">
        UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}
    </update>

    <delete id="deleteUser">
        DELETE FROM users WHERE id = #{id}
    </delete>
</mapper>

src/main/java/com/example/demo/repository 目录下创建 UserRepository.java

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.ResultMap;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface UserRepository {

    @Select("SELECT * FROM users")
    List<User> getAllUsers();

    @Select("SELECT * FROM users WHERE id = #{id}")
    User getUserById(@Param("id") Long id);

    @Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})")
    void createUser(User user);

    @Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
    void updateUser(@Param("id") Long id, @Param("user") User user);

    @Delete("DELETE FROM users WHERE id = #{id}")
    void deleteUser(@Param("id") Long id);
}

数据库连接与事务管理

事务管理

Spring Boot 内置了事务管理功能,通过 @Transactional 注解来启用事务支持。

示例代码

src/main/java/com/example/demo/service 目录下创建 TransactionService.java

package com.example.demo.service;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class TransactionService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUserWithTransaction(User user) {
        userRepository.save(user);
        // Simulate an exception to rollback the transaction
        throw new RuntimeException("Simulated exception");
    }

    @Transactional
    public void createUserWithoutException(User user) {
        userRepository.save(user);
    }
}
异步与WebSocket

Spring Boot异步任务处理

Spring Boot 支持异步任务处理,可以使用 @Async 注解来实现。

示例代码

src/main/java/com/example/demo/task 目录下创建 TaskService.java

package com.example.demo.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class TaskService {

    @Async
    public void performLongRunningTask() {
        // Simulate a long-running task
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Task completed");
    }
}

src/main/java/com/example/demo/controller 目录下创建 AsyncTaskController.java

package com.example.demo.controller;

import com.example.demo.task.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AsyncTaskController {

    @Autowired
    private TaskService taskService;

    @GetMapping("/async")
    public String triggerAsyncTask() {
        taskService.performLongRunningTask();
        return "Task triggered asynchronously";
    }
}

src/main/java/com/example/demo 目录下的 DemoApplication.java 中添加 @EnableAsync 注解:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

WebSocket基本概念

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它让服务器端主动向客户端推送数据成为可能,从而可以更好地实现实时通信和推送功能。

WebSocket聊天室案例演示

src/main/java/com/example/demo 目录下创建 WebSocketConfig.java

package com.example.demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(chatHandler(), "/chat").setAllowedOrigins("*").withInterceptors(new HttpSessionHandshakeInterceptor());
    }

    @Bean
    public ChatHandler chatHandler() {
        return new ChatHandler();
    }
}

src/main/java/com/example/demo 目录下创建 ChatHandler.java

package com.example.demo;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ChatHandler extends TextWebSocketHandler {

    private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.put(session.getId(), session);
        System.out.println("New client connected: " + session.getId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session.getId());
        System.out.println("Client disconnected: " + session.getId());
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("Received message: " + payload);

        // Broadcast the message to all connected clients
        sessions.values().forEach(s -> {
            if (s.isOpen()) {
                try {
                    s.sendMessage(new TextMessage(payload));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

src/main/resources/templates 目录下创建 chat.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>WebSocket Chat</title>
    <script>
        var socket = new WebSocket("ws://localhost:8080/chat");

        socket.onmessage = function(event) {
            var message = document.createElement("div");
            message.textContent = event.data;
            document.getElementById("messages").appendChild(message);
        };

        function sendMessage() {
            var input = document.getElementById("message");
            socket.send(input.value);
            input.value = "";
        }
    </script>
</head>
<body>
    <h1>WebSocket Chat</h1>
    <div id="messages"></div>
    <input id="message" type="text" onkeypress="if (event.keyCode == 13) sendMessage();"/>
    <button onclick="sendMessage()">Send</button>
</body>
</html>

src/main/java/com/example/demo/controller 目录下创建 ChatController.java

package com.example.demo.controller;

import com.example.demo.WebSocketConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RestController
public class ChatController {

    @GetMapping("/chat")
    public ModelAndView chat() {
        return new ModelAndView("chat");
    }
}
日志与监控

Log4j2与SLF4J日志框架

SLF4J(Simple Logging Facade for Java)是一个简单的日志门面(Facade),它提供了多个实现(如 Log4j、Logback 等)的抽象。Spring Boot 默认使用 Logback 作为日志实现,但也可以配置使用 Log4j2。

示例代码

src/main/resources/log4j2.xml 中配置 Log4j2 日志框架:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        <File name="File" fileName="app.log">
            <PatternLayout pattern="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/>
        </File>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Root>
    </Loggers>
</Configuration>

src/main/resources/application.properties 中启用 Log4j2 配置:

logging.config=classpath:log4j2.xml

src/main/java/com/example/demo 目录下的 DemoApplication.java 中添加日志输出:

package com.example.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    private static final Logger logger = LoggerFactory.getLogger(DemoApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
        logger.info("Application Started");
    }

}

Spring Boot Actuator监控

Spring Boot Actuator 是一个模块,它提供了生产就绪功能,例如健康检查、指标收集、审计、远程刷新等。它允许您更好地了解您的应用程序并管理它。

示例代码

pom.xmlbuild.gradle 文件中添加 Actuator 依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.5.3</version>
</dependency>
// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-actuator:2.5.3'

src/main/resources/application.properties 中添加 Actuator 配置:

management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always

启动应用程序后,访问 /actuator 路径,可以看到所有暴露的端点。

热部署与Spring Boot DevTools

Spring Boot DevTools 提供了热部署功能,可以简化开发流程。

示例代码

pom.xmlbuild.gradle 文件中添加 DevTools 依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <version>2.5.3</version>
    <scope>runtime</scope>
</dependency>
// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-devtools:2.5.3'
}

使用 mvn spring-boot:rungradle bootRun 命令启动应用,每次保存文件时,应用会自动重新启动。

安全与权限控制

Spring Security基本配置

Spring Security 是一个强大的安全框架,提供认证和授权功能。

示例代码

pom.xmlbuild.gradle 文件中添加 Security 依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.5.3</version>
</dependency>
// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-security:2.5.3'

src/main/java/com/example/demo 目录下创建 SecurityConfig.java

package com.example.demo;

import org.springframework.context.annotation.Bean;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password(passwordEncoder().encode("password")).roles("USER")
                .and()
                .withUser("admin").password(passwordEncoder().encode("password")).roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/admin/**").hasRole("ADMIN")
                    .antMatchers("/user/**").hasRole("USER")
                    .anyRequest().permitAll()
                .and()
                    .formLogin()
                    .loginPage("/login")
                    .permitAll()
                .and()
                    .logout()
                    .logoutUrl("/logout")
                    .permitAll();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

用户认证与授权

src/main/java/com/example/demo 目录下创建 SecurityController.java

package com.example.demo;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SecurityController {

    @GetMapping("/user")
    public Principal user(@AuthenticationPrincipal OidcUser oidcUser) {
        return oidcUser;
    }
}

src/main/resources/templates 目录下创建 login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form action="/login" method="POST">
        <input type="text" name="username" placeholder="Username" required />
        <input type="password" name="password" placeholder="Password" required />
        <input type="submit" value="Login" />
    </form>
</body>
</html>

认证令牌与JWT技术介绍

JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络应用环境间安全地将信息作为JSON对象传输。

示例代码

src/main/java/com/example/demo/security 目录下创建 JwtAuthenticationFilter.java

package com.example.demo.security;

import at.favre.lib.crypto.bcrypt.BCrypt;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    private UserRepository userRepository;

    public JwtAuthenticationFilter(AuthenticationManager authManager, UserRepository userRepository) {
        super(authManager);
        this.userRepository = userRepository;
    }

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String token = request.getHeader("Authorization");
        if (token != null) {
            String username = Jwts.parser().setSigningKey("secret".getBytes()).parseClaimsJws(token).getBody().getSubject();
            if (username != null) {
                User user = userRepository.findByUsername(username);
                if (user != null) {
                    Authentication auth = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                    SecurityContextHolder.getContext().setAuthentication(auth);
                }
            }
        }
        filterChain.doFilter(request, response);
    }
}

src/main/java/com/example.demo.security 目录下创建 JwtTokenProvider.java

package com.example.demo.security;

import at.favre.lib.crypto.bcrypt.BCrypt;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.stream.Collectors;

@Component
public class JwtTokenProvider {

    private UserRepository userRepository;
    private BCrypt bCrypt;

    public JwtTokenProvider(UserRepository userRepository) {
        this.userRepository = userRepository;
        this.bCrypt = BCrypt.withDefaults();
    }

    public String generateToken(UserDetails userDetails) {
        String authorities = userDetails.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(","));

        long now = (new Date()).getTime();
        Date validity = new Date(now + 3600000);

        return Jwts.builder()
                .setSubject(userDetails.getUsername())
                .claim("authorities", authorities)
                .setIssuedAt(new Date())
                .setExpiration(validity)
                .signWith(SignatureAlgorithm.HS256, "secret".getBytes())
                .compact();
    }

    public Authentication getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null) {
            Claims claims = Jwts.parser().setSigningKey("secret".getBytes()).parseClaimsJws(token).getBody();

            String username = claims.getSubject();
            if (username != null) {
                User user = userRepository.findByUsername(username);
                if (user != null) {
                    return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
                }
            }
        }
        return null;
    }

    public boolean validateToken(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null) {
            Claims claims = Jwts.parser().setSigningKey("secret".getBytes()).parseClaimsJws(token).getBody();
            if (claims.getExpiration().after(new Date())) {
                return true;
            }
        }
        return false;
    }
}

src/main/java/com/example.demo.security 目录下创建 JwtTokenFilter.java

package com.example.demo.security;

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;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                    .antMatchers("/auth/**").permitAll()
                    .anyRequest().authenticated()
                .and()
                    .addFilterBefore(new JwtTokenFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class);
    }
}

src/main/java/com/example.demo.controller 目录下创建 AuthController.java

package com.example.demo.controller;

import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import com.example.demo.security.JwtTokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private UserRepository userRepository;
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @PostMapping("/login")
    public String login(@RequestParam String username, @RequestParam String password) {
        User user = userRepository.findByUsername(username);
        if (user != null && bCryptPasswordEncoder.matches(password, user.getPassword())) {
            return jwtTokenProvider.generateToken(user);
        }
        return null;
    }

    @PostMapping("/register")
    public String register(@RequestParam String username, @RequestParam String password) {
        User user = new User();
        user.setUsername(username);
        user.setPassword(bCryptPasswordEncoder.encode(password));
        userRepository.save(user);
        return jwtTokenProvider.generateToken(user);
    }
}

src/main/java/com/example.demo.entity 目录下创建 User.java

package com.example.demo.entity;

import org.springframework.security.core.GrantedAuthority;

public class User extends org.springframework.security.core.userdetails.User {

    public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
    }

    public User(String username, String password) {
        super(username, password, new SimpleGrantedAuthority("ROLE_USER"));
    }
}

src/main/java/com/example.demo.repository 目录下创建 UserRepository.java

package com.example.demo.repository;

import com.example.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);
}

通过以上示例代码,实现了基本的用户认证和授权功能,以及 JWT 的使用。

这些代码示例和配置展示了如何在 Spring Boot 应用中集成 Spring Security 和 JWT 进行安全控制,确保应用程序的安全性。

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消