Java一一一简易图书管理系统
1. 需求分析
- 功能需求:
- 添加图书
- 删除图书
- 更新图书信息
- 查询图书
- 列出所有图书
2. 设计
- 实体类:
Book
- 业务逻辑类:
LibraryManager
3. 实现
3.1 Book类
public class Book {
private String id;
private String title;
private String author;
private int year;
public Book(String id, String title, String author, int year) {
this.id = id;
this.title = title;
this.author = author;
this.year = year;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "Book{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", author='" + author + '\'' +
", year=" + year +
'}';
}
}
3.2 LibraryManager类
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class LibraryManager {
private List<Book> books;
public LibraryManager() {
this.books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public boolean removeBook(String id) {
return books.removeIf(book -> book.getId().equals(id));
}
public void updateBook(String id, Book updatedBook) {
Book book = books.stream()
.filter(b -> b.getId().equals(id))
.findFirst()
.orElse(null);
if (book != null) {
book.setTitle(updatedBook.getTitle());
book.setAuthor(updatedBook.getAuthor());
book.setYear(updatedBook.getYear());
}
}
public List<Book> searchBooksByTitle(String title) {
return books.stream()
.filter(book -> book.getTitle().contains(title))
.collect(Collectors.toList());
}
public List<Book> getAllBooks() {
return new ArrayList<>(books);
}
}
4. 测试
public class Main {
public static void main(String[] args) {
LibraryManager manager = new LibraryManager();
// 添加图书
manager.addBook(new Book("1", "Java Basics", "John Doe", 2021));
manager.addBook(new Book("2", "Advanced Java", "Jane Doe", 2022));
// 列出所有图书
System.out.println("All Books:");
manager.getAllBooks().forEach(System.out::println);
// 更新图书
Book updatedBook = new Book("1", "Java Fundamentals", "John Doe", 2021);
manager.updateBook("1", updatedBook);
// 搜索图书
System.out.println("Search Results:");
manager.searchBooksByTitle("Java").forEach(System.out::println);
// 删除图书
manager.removeBook("2");
// 再次列出所有图书
System.out.println("All Books after removal:");
manager.getAllBooks().forEach(System.out::println);
}
}
5. 总结
这个简易的图书管理系统展示了Java在面向对象编程中的基本应用,包括类的定义、方法的实现以及简单的集合操作。通过这个案例,初学者可以学习到如何使用Java创建和管理对象集合,以及如何实现简单的业务逻辑。
请注意,这只是一个基础示例,实际应用中可能需要考虑更多的功能和异常处理,以及与数据库的交互等。
案例名称:基于Spring Boot的RESTful图书管理系统
1. 环境准备
- Java 11 或更高版本
- Spring Boot 2.5.x 或更高版本
- Maven 或 Gradle 作为构建工具
- 一个文本编辑器或IDE(如IntelliJ IDEA或Eclipse)
2. 项目结构
src/
|-- main/
| |-- java/
| | `-- com.example.bookstore/
| | |-- BookController.java
| | |-- BookService.java
| | `-- Book.java
| `-- resources/
| `-- application.properties
3. 实现步骤
3.1 创建Spring Boot项目
使用Spring Initializr来生成项目基础结构。
3.2 添加依赖
在pom.xml
(Maven)或build.gradle
(Gradle)中添加Web和JPA依赖。
pom.xml 示例:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
3.3 Book实体类
package com.example.bookstore;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String author;
private int publishYear;
// Constructors, getters and setters
}
3.4 BookRepository接口
package com.example.bookstore;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookRepository extends JpaRepository<Book, Long> {
}
3.5 BookService业务逻辑类
package com.example.bookstore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
public List<Book> getAllBooks() {
return bookRepository.findAll();
}
public Book getBookById(Long id) {
return bookRepository.findById(id).orElse(null);
}
public Book addBook(Book book) {
return bookRepository.save(book);
}
public Book updateBook(Long id, Book updatedBook) {
Optional<Book> bookOptional = bookRepository.findById(id);
if (bookOptional.isPresent()) {
Book book = bookOptional.get();
book.setTitle(updatedBook.getTitle());
book.setAuthor(updatedBook.getAuthor());
book.setPublishYear(updatedBook.getPublishYear());
return bookRepository.save(book);
}
return null;
}
public void deleteBook(Long id) {
bookRepository.deleteById(id);
}
}
3.6 BookController控制器
package com.example.bookstore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
@GetMapping("/{id}")
public ResponseEntity<Book> getBookById(@PathVariable Long id) {
Book book = bookService.getBookById(id);
return book != null ? ResponseEntity.ok(book) : ResponseEntity.notFound().build();
}
@PostMapping
public Book addBook(@RequestBody Book book) {
return bookService.addBook(book);
}
@PutMapping("/{id}")
public ResponseEntity<Book> updateBook(@PathVariable Long id, @RequestBody Book updatedBook) {
Book book = bookService.updateBook(id, updatedBook);
return book != null ? ResponseEntity.ok(book) : ResponseEntity.notFound().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
return ResponseEntity.ok().build();
}
}
3.7 配置文件application.properties
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
4. 运行和测试
使用您喜欢的IDE运行main
方法或使用Maven/Gradle命令来启动Spring Boot应用。使用Postman或curl命令行工具来测试API。
5. 总结
这个案例展示了如何使用Spring Boot创建一个简单的RESTful API,它提供了基本的CRUD操作。通过这个案例,您可以学习到Spring Boot的核心概念,如依赖注入、服务层、数据访问层以及RESTful API设计。
这个示例使用了内存数据库H2,适合开发和测试,但在生产环境中,您应该使用更健壮的数据库解决方案,并考虑安全性、异常处理和日志记录等因素。
接下来,我们将在图书管理系统中增加一个新功能:用户认证和授权。我们将使用Spring Security来实现这一功能,确保只有认证用户可以访问敏感数据和执行特定操作。
带有用户认证和授权的图书管理系统
1. 添加Spring Security依赖
首先,需要在项目的pom.xml
(Maven)或build.gradle
(Gradle)文件中添加Spring Security的依赖。
pom.xml 示例:
<dependencies>
<!-- ... other dependencies ... -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
2. 配置Spring Security
创建一个配置类来配置Spring Security。
package com.example.bookstore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(
User.withUsername("user")
.password(encoder.encode("password"))
.roles("USER")
.build()
);
return manager;
}
@Bean
public HttpSecurity httpSecurity(UserDetailsService userDetailsService) throws Exception {
return new HttpSecurity(http -> http
.authorizeRequests()
.antMatchers("/api/books/**").authenticated()
.and()
.httpBasic()
.and()
.csrf().disable()
);
}
}
3. 保护RESTful API
使用@PreAuthorize
注解来保护特定的API端点。
package com.example.bookstore;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/books")
public class BookController {
// ... existing code ...
@PreAuthorize("hasRole('USER')")
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
bookService.deleteBook(id);
return ResponseEntity.ok().build();
}
}
4. 增加用户注册功能
创建一个用户注册的API端点。
// ... existing imports ...
@RestController
@RequestMapping("/api/auth")
public class AuthController {
private final UserService userService;
public AuthController(UserService userService) {
this.userService = userService;
}
@PostMapping("/register")
public ResponseEntity<?> registerUser(@RequestBody UserRegistrationDto userRegistrationDto) {
userService.registerUser(userRegistrationDto);
return ResponseEntity.ok().build();
}
}
5. 用户注册服务和数据传输对象
创建UserService
和UserRegistrationDto
来处理用户注册。
package com.example.bookstore;
// UserService.java
@Service
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public void registerUser(UserRegistrationDto userRegistrationDto) {
User newUser = new User(
userRegistrationDto.getUsername(),
passwordEncoder.encode(userRegistrationDto.getPassword())
);
userRepository.save(newUser);
}
}
// UserRegistrationDto.java
public class UserRegistrationDto {
private String username;
private String password;
// Constructors, getters and setters
}
6. 更新数据库配置
在application.properties
或application.yml
中添加用户表的配置。
# application.properties
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
# H2 console settings
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
7. 测试和验证
启动应用程序,并使用Postman或curl测试用户注册和认证保护的API。
8. 总结
通过增加用户认证和授权,我们的图书管理系统变得更加安全。Spring Security提供了一套强大的安全工具,可以轻松地集成到Spring Boot应用程序中。通过使用@EnableWebSecurity
注解和配置HttpSecurity
,我们可以控制对API端点的访问。此外,@PreAuthorize
注解允许我们在方法级别细粒度地控制访问权限。
请注意,本案例中的用户存储在内存中,仅用于演示目的。在实际应用中,您应该使用数据库来持久化用户信息,并考虑使用JWT或OAuth2等更先进的认证机制。
接下来,我们将在图书管理系统中增加一个新功能:基于角色的访问控制(RBAC)。这将允许我们根据用户的角色限制对某些资源的访问。
基于角色的访问控制的图书管理系统
1. 扩展用户模型
首先,我们需要扩展用户模型来包含角色信息。
package com.example.bookstore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.persistence.*;
import java.util.Collection;
import java.util.stream.Collectors;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
private Set<Role> roles;
// Constructors, getters and setters
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
2. 角色模型
创建一个角色模型来定义不同的角色。
package com.example.bookstore;
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Constructors, getters and setters
}
3. 用户角色关联
创建一个关联表来定义用户和角色之间的关系。
package com.example.bookstore;
import javax.persistence.*;
@Entity
@Table(name = "user_role")
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "role_id")
private Role role;
// Constructors, getters and setters
}
4. 更新UserRepository
添加方法来查找用户及其角色。
package com.example.bookstore;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
5. 更新Spring Security配置
更新SecurityConfig
来使用自定义的UserDetailsService
。
package com.example.bookstore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository userRepository;
@Bean
@Override
public UserDetailsService userDetailsService() {
return new UserDetailsManager() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return user;
}
// Other methods are omitted for brevity
};
}
// Other configurations are omitted for brevity
}
6. 基于角色的访问控制
使用@PreAuthorize
或@Secured
注解来限制访问。
package com.example.bookstore;
import org.springframework.security.access.prepost.PreAuthorize;
@RestController
@RequestMapping("/api/books")
public class BookController {
// ... existing code ...
@PreAuthorize("hasRole('ADMIN')")
@PostMapping
public Book addBook(@RequestBody Book book) {
return bookService.addBook(book);
}
@PreAuthorize("hasRole('USER')")
@GetMapping
public List<Book> getAllBooks() {
return bookService.getAllBooks();
}
}
7. 用户角色管理
创建API端点来管理用户角色。
package com.example.bookstore;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping("/{username}/roles")
public ResponseEntity<?> addRoleToUser(@PathVariable String username, @RequestBody RoleRequestDto roleRequestDto) {
userService.addRoleToUser(username, roleRequestDto.getRoleName());
return ResponseEntity.ok().build();
}
}
// RoleRequestDto.java
public class RoleRequestDto {
private String roleName;
// Constructors, getters and setters
}
8. 测试和验证
启动应用程序,并使用Postman或curl测试基于角色的访问控制。
9. 总结
通过实现基于角色的访问控制,我们的图书管理系统可以更细致地控制用户对资源的访问。这在多用户应用中尤为重要,可以确保用户只能访问他们被授权的资源。
这个案例演示了如何在Spring Security中使用自定义的UserDetailsService
来加载用户及其角色信息,以及如何使用@PreAuthorize
注解来实现基于角色的访问控制。在实际应用中,您可能还需要实现更复杂的用户和角色管理功能,以及更细粒度的权限控制策略。