diff --git a/docs/tasks/chapter05-tasks.md b/docs/tasks/chapter05-tasks.md new file mode 100644 index 0000000..f01a42a --- /dev/null +++ b/docs/tasks/chapter05-tasks.md @@ -0,0 +1,315 @@ +## 5. 基于Spring框架的后端应用开发 + +### 5.1 Java基础增强 + +#### 5.1.1 Java异常处理 + +**练习任务**: +1. **异常处理练习**: + - 创建一个方法,该方法接受两个整数参数,并返回它们的除法结果。如果第二个参数为0,则抛出自定义异常。 + - 在主程序中调用该方法,并使用try-catch块来捕获异常,输出友好的错误信息。 + - 示例代码: + ```java + public class Division { + public static double divide(int a, int b) throws IllegalArgumentException { + if (b == 0) { + throw new IllegalArgumentException("除数不能为0"); + } + return (double) a / b; + } + + public static void main(String[] args) { + try { + double result = divide(10, 0); + System.out.println("结果: " + result); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + } + } + } + ``` + +2. **自定义异常练习**: + - 创建一个自定义异常类`InvalidAgeException`,继承自`IllegalArgumentException`。 + - 创建一个方法`validateAge`,接收一个年龄参数,如果年龄小于0或大于150,则抛出`InvalidAgeException`。 + - 在主程序中调用`validateAge`方法,并捕获异常,输出异常信息。 + - 示例代码: + ```java + public class AgeValidator { + public static void validateAge(int age) throws InvalidAgeException { + if (age < 0 || age > 150) { + throw new InvalidAgeException("年龄无效"); + } + } + + public static void main(String[] args) { + try { + validateAge(-5); + } catch (InvalidAgeException e) { + System.out.println(e.getMessage()); + } + } + } + + class InvalidAgeException extends IllegalArgumentException { + public InvalidAgeException(String message) { + super(message); + } + } + ``` + +#### 5.1.2 注解 + +**练习任务**: +1. **自定义注解练习**: + - 创建一个自定义注解`@MyAnnotation`,并带有字符串属性`value`。 + - 创建一个类`AnnotatedClass`,并在其方法上使用`@MyAnnotation`注解。 + - 编写一个程序读取该注解,并打印出注解的值。 + - 示例代码: + ```java + import java.lang.reflect.Method; + + public @interface MyAnnotation { + String value(); + } + + public class AnnotatedClass { + @MyAnnotation(value = "Hello, Annotation!") + public void myMethod() { + // 方法实现 + } + + public static void main(String[] args) { + Method[] methods = AnnotatedClass.class.getDeclaredMethods(); + for (Method method : methods) { + MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); + if (annotation != null) { + System.out.println(annotation.value()); + } + } + } + } + ``` + +#### 5.1.3 Optional的介绍和使用 + +**练习任务**: +1. **Optional练习**: + - 创建一个方法`getUserById`,该方法接收一个ID参数,并返回一个`Optional`对象。 + - 如果ID对应的数据存在,则返回包含用户对象的`Optional`;否则返回空的`Optional`。 + - 在主程序中调用该方法,并使用`ifPresent`或`orElse`方法处理结果。 + - 示例代码: + ```java + public class User { + private String name; + + public User(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + public class UserService { + public static Optional getUserById(long id) { + if (id == 1) { + return Optional.of(new User("John Doe")); + } else { + return Optional.empty(); + } + } + + public static void main(String[] args) { + Optional user = getUserById(1); + user.ifPresent(u -> System.out.println("用户姓名: " + u.getName())); + } + } + ``` + +#### 5.1.4 Stream API的介绍和使用 + +**练习任务**: +1. **Stream API练习**: + - 创建一个方法`findMaxValue`,该方法接收一个`List`参数,并返回列表中的最大值。 + - 使用Stream API来实现这个功能。 + - 示例代码: + ```java + import java.util.Arrays; + import java.util.List; + + public class MaxFinder { + public static int findMaxValue(List numbers) { + return numbers.stream().max(Integer::compare).orElse(0); + } + + public static void main(String[] args) { + List numbers = Arrays.asList(1, 2, 3, 4, 5); + int maxValue = findMaxValue(numbers); + System.out.println("最大值: " + maxValue); + } + } + ``` + +#### 5.1.5 泛型 + +**练习任务**: +1. **泛型练习**: + - 创建一个泛型类`Pair`,用于存储两个不同类型的数据。 + - 在主程序中创建一个`Pair`对象,并设置和获取其中的值。 + - 示例代码: + ```java + public class Pair { + private T first; + private U second; + + public Pair(T first, U second) { + this.first = first; + this.second = second; + } + + public T getFirst() { + return first; + } + + public U getSecond() { + return second; + } + + public void setFirst(T first) { + this.first = first; + } + + public void setSecond(U second) { + this.second = second; + } + } + + public class Main { + public static void main(String[] args) { + Pair pair = new Pair<>("Hello", 42); + System.out.println("First: " + pair.getFirst() + ", Second: " + pair.getSecond()); + } + } + ``` + +### 5.2 Spring框架简介 + +#### 5.2.2 Spring框架的核心特性 + +**练习任务**: +1. **Spring框架特性练习**: + - 使用Spring框架创建一个简单的Web应用,该应用包含一个控制器,该控制器提供一个静态的欢迎页面。 + - 示例代码: + ```java + import org.springframework.stereotype.Controller; + import org.springframework.web.bind.annotation.GetMapping; + + @Controller + public class WelcomeController { + @GetMapping("/") + public String welcome() { + return "welcome"; + } + } + ``` + +### 5.3 Spring IoC + +#### 5.3.1 Spring Bean的定义和生命周期 + +**练习任务**: +1. **Bean生命周期练习**: + - 创建一个带有初始化和销毁方法的Spring Bean。 + - 使用`@PostConstruct`和`@PreDestroy`注解来标记初始化和销毁方法。 + - 示例代码: + ```java + import org.springframework.stereotype.Component; + + @Component + public class LifeCycleBean { + public LifeCycleBean() { + System.out.println("LifeCycleBean created."); + } + + @PostConstruct + public void init() { + System.out.println("LifeCycleBean initialized."); + } + + @PreDestroy + public void destroy() { + System.out.println("LifeCycleBean destroyed."); + } + } + ``` + +#### 5.3.2 XML和注解方式的Bean配置 + +**练习任务**: +1. **XML和注解配置练习**: + - 使用XML和注解两种方式配置一个简单的Spring Bean。 + - 在主程序中获取并使用该Bean。 + - 示例代码 (XML配置): + ```xml + + + + + + + + + ``` + + - 示例代码 (注解配置): + ```java + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + + @Configuration + public class AppConfig { + @Bean + public MyBean myBean() { + return new MyBean("Jane Doe"); + } + } + + public class MyBean { + private String name; + + public MyBean(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + ``` + +### 5.4 Spring MVC + +#### 5.4.2 使用@Controller定义控制器 + +**练习任务**: +1. **控制器练习**: + - 创建一个简单的控制器,该控制器接收一个GET请求并返回一个简单的HTML页面。 + - 示例代码: + ```java + import org.springframework.stereotype.Controller; + import org.springframework.web.bind.annotation.GetMapping; + + @Controller + public class SimpleController { + @GetMapping("/simple") + public String simplePage() { + return "simple"; + } + } + ``` + diff --git a/docs/tasks/chapter06-tasks.md b/docs/tasks/chapter06-tasks.md new file mode 100644 index 0000000..0ff7ec7 --- /dev/null +++ b/docs/tasks/chapter06-tasks.md @@ -0,0 +1,220 @@ +## 6. 数据库访问 +### 6.1 JDBC + +#### 6.1.3 实现第一个JDBC程序 + +**练习任务**: + +1. **创建数据库表**: + - 根据PetClinic中的`Owner`实体模型创建一个表,包含`id`(整数,主键,自增)、`firstName`(字符串,长度255,不可为空)、`lastName`(字符串,长度255,不可为空)、`address`(字符串,长度255)、`city`(字符串,长度255)、`telephone`(字符串,长度255)字段。 + - 示例代码: + ```java + private static void createOwnerTable(Connection conn) throws SQLException { + String sql = "CREATE TABLE IF NOT EXISTS owners (" + + "id INT AUTO_INCREMENT PRIMARY KEY," + + "firstName VARCHAR(255) NOT NULL," + + "lastName VARCHAR(255) NOT NULL," + + "address VARCHAR(255)," + + "city VARCHAR(255)," + + "telephone VARCHAR(255))"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.executeUpdate(); + } + } + ``` + +2. **插入业主记录**: + - 向`owners`表中插入两条记录。 + - 示例代码: + ```java + private static void insertOwners(Connection conn) throws SQLException { + String sql = "INSERT INTO owners (firstName, lastName, address, city, telephone) VALUES (?, ?, ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, "Alice"); + pstmt.setString(2, "Johnson"); + pstmt.setString(3, "123 Main St"); + pstmt.setString(4, "Springfield"); + pstmt.setString(5, "555-1234"); + pstmt.executeUpdate(); + + pstmt.setString(1, "Bob"); + pstmt.setString(2, "Smith"); + pstmt.setString(3, "456 Elm St"); + pstmt.setString(4, "Springfield"); + pstmt.setString(5, "555-5678"); + pstmt.executeUpdate(); + } + } + ``` + +3. **查询业主记录**: + - 查询`owners`表中的所有记录,并打印出每条记录的信息。 + - 示例代码: + ```java + private static void queryOwners(Connection conn) throws SQLException { + String sql = "SELECT * FROM owners"; + try (PreparedStatement pstmt = conn.prepareStatement(sql); + ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + int id = rs.getInt("id"); + String firstName = rs.getString("firstName"); + String lastName = rs.getString("lastName"); + String address = rs.getString("address"); + String city = rs.getString("city"); + String telephone = rs.getString("telephone"); + System.out.println("ID: " + id + ", First Name: " + firstName + ", Last Name: " + lastName + ", Address: " + address + ", City: " + city + ", Telephone: " + telephone); + } + } + } + ``` + +4. **更新业主记录**: + - 更新`owners`表中名字为"Alice Johnson"的业主的电话号码为"555-1111"。 + - 示例代码: + ```java + private static void updateOwner(Connection conn) throws SQLException { + String sql = "UPDATE owners SET telephone = ? WHERE firstName = ? AND lastName = ?"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, "555-1111"); + pstmt.setString(2, "Alice"); + pstmt.setString(3, "Johnson"); + int rowsUpdated = pstmt.executeUpdate(); + System.out.println(rowsUpdated + " row(s) updated."); + } + } + ``` + +5. **删除业主记录**: + - 删除`owners`表中名字为"Bob Smith"的业主记录。 + - 示例代码: + ```java + private static void deleteOwner(Connection conn) throws SQLException { + String sql = "DELETE FROM owners WHERE firstName = ? AND lastName = ?"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, "Bob"); + pstmt.setString(2, "Smith"); + int rowsDeleted = pstmt.executeUpdate(); + System.out.println(rowsDeleted + " row(s) deleted."); + } + } + ``` + +6. **完整程序**: + - 将以上步骤整合到一个完整的程序中,确保正确加载MySQL驱动、建立数据库连接,并处理异常。 + - 示例代码: + ```java + import java.sql.Connection; + import java.sql.DriverManager; + import java.sql.SQLException; + + public class JdbcCrudExample { + private static final String DB_URL = "jdbc:mysql://localhost:3306/petclinic"; + private static final String USER = "root"; + private static final String PASS = "password"; + + public static void main(String[] args) { + Connection conn = null; + try { + // 加载MySQL驱动 + Class.forName("com.mysql.cj.jdbc.Driver"); + + // 获取数据库连接 + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 创建表 + createOwnerTable(conn); + + // 插入记录 + insertOwners(conn); + + // 查询记录 + queryOwners(conn); + + // 更新记录 + updateOwner(conn); + + // 删除记录 + deleteOwner(conn); + + // 再次查询记录 + queryOwners(conn); + + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } finally { + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + } + + // 其他方法... + } + ``` + +### 6.3 SQL注入的预防措施 + +**练习任务**: + +1. **使用PreparedStatement防止SQL注入**: + - 修改上述的`queryOwners`方法,使用`PreparedStatement`来执行查询。 + - 示例代码: + ```java + private static void queryOwners(Connection conn) throws SQLException { + String sql = "SELECT * FROM owners WHERE firstName = ? AND lastName = ?"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, "Alice"); + pstmt.setString(2, "Johnson"); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + int id = rs.getInt("id"); + String firstName = rs.getString("firstName"); + String lastName = rs.getString("lastName"); + String address = rs.getString("address"); + String city = rs.getString("city"); + String telephone = rs.getString("telephone"); + System.out.println("ID: " + id + ", First Name: " + firstName + ", Last Name: " + lastName + ", Address: " + address + ", City: " + city + ", Telephone: " + telephone); + } + } + } + ``` + +### 6.2 数据库连接池 + +#### 6.2.4 使用HikariCP实现数据库连接池 + +**练习任务**: + +1. **配置HikariCP连接池**: + - 使用HikariCP配置一个连接池,并使用它来获取数据库连接。 + - 示例代码: + ```java + import com.zaxxer.hikari.HikariConfig; + import com.zaxxer.hikari.HikariDataSource; + import java.sql.Connection; + import java.sql.SQLException; + + public class HikariCpExample { + public static void main(String[] args) { + HikariConfig config = new HikariConfig(); + config.setJdbcUrl("jdbc:mysql://localhost:3306/petclinic"); + config.setUsername("root"); + config.setPassword("password"); + config.setMaximumPoolSize(10); + config.setConnectionTimeout(30000); + + HikariDataSource ds = new HikariDataSource(config); + + try (Connection conn = ds.getConnection()) { + // 使用连接执行数据库操作 + System.out.println("Database connection established."); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + ``` diff --git a/docs/todo.md b/docs/todo.md new file mode 100644 index 0000000..a87600a --- /dev/null +++ b/docs/todo.md @@ -0,0 +1,13 @@ + +mvc开源项目参考 https://gitee.com/YHC/book-JavaEE-SSM + +spring petclinic https://gitee.com/phxism/spring-framework-petclinic + + +https://gitee.com/univerciti/java-ee-spring-pet-clinic + + +https://github.com/FlaviodosSantos/TutorialSpringMVC + + +**https://github.com/spring-petclinic/spring-framework-petclinic**