Java 简历项目实战教程从搭建开发环境开始,涵盖了Java基础知识、集合框架和异常处理等核心内容,展示了如何创建和展示简历信息的完整流程,帮助开发者掌握从零开始构建简历项目的技能。
Java 基础知识回顾Java 语言简介
Java 是一种广泛使用的面向对象的编程语言,由 James Gosling 在 Sun Microsystems(现在是 Oracle 的一部分)开发。Java 语言的设计目标之一是编写一次,到处运行,这意味着用 Java 编写的程序可以运行在任何安装了 Java 虚拟机(JVM)的操作系统上。Java 还提供了一些特性,如自动内存管理和垃圾回收,这些特性使得 Java 程序的开发和维护变得更加简单和安全。
Java 开发环境搭建
在开发 Java 应用程序之前,首先需要搭建 Java 开发环境。这通常包括安装 JDK(Java Development Kit)和一个集成开发环境(IDE)。以下是搭建步骤:
-
安装 JDK:
- 访问 Oracle 官方网站或 Adoptium 网站下载对应操作系统的 JDK。
- 安装 JDK,确保安装路径正确,并将 JDK 的 bin 目录添加到系统的环境变量 PATH 中。
-
安装 IDE:
- Eclipse:一个流行的集成开发环境,支持多种编程语言。
- IntelliJ IDEA:一个功能强大的 Java 开发环境,支持多种语言和框架。
- NetBeans:一个开源的集成开发环境,支持多种编程语言。
- 配置 IDE:
- 打开 Eclipse 或 IntelliJ IDEA,创建一个新的 Java 项目。
- 确保 JDK 已正确配置,并在项目中使用。
例如,使用 IntelliJ IDEA 创建新项目:
File -> New -> Project
选择 Java
,并填写项目名称和位置,然后点击 Finish
。
Java 基本语法和常用数据类型
Java 语言的语法和常用数据类型是进行 Java 开发的基础。
变量与类型
Java 中的变量类型可以分为基本数据类型和引用数据类型。
- 基本数据类型包括
byte
、short
、int
、long
、float
、double
、char
和boolean
。 - 引用数据类型包括类(class)、接口(interface)和数组(array)。
定义变量的示例代码:
public class Main {
public static void main(String[] args) {
// 基本数据类型
int age = 25;
double salary = 3400.50;
boolean isEmployed = true;
char initial = 'J';
// 引用数据类型
String name = "John Doe";
int[] numbers = {1, 2, 3, 4, 5};
}
}
常量
常量是在程序运行过程中不会改变的值,通常使用 final
关键字定义。
public class Main {
public static void main(String[] args) {
final double PI = 3.14159;
System.out.println("PI: " + PI);
}
}
运算符
Java 支持常见的算术运算符、关系运算符、逻辑运算符等。
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 20;
// 算术运算符
int sum = a + b;
int diff = a - b;
int product = a * b;
int quotient = a / b;
int remainder = a % b;
// 关系运算符
boolean isEqual = (a == b);
boolean isNotEqual = (a != b);
// 逻辑运算符
boolean andResult = (a > 0) && (b > 0);
boolean orResult = (a > 0) || (b > 0);
}
}
Java 基本输入输出操作
Java 提供了多种输入输出流来处理文件和控制台输入输出。
文件输入输出
使用 FileInputStream
和 FileOutputStream
处理文件的读写操作。
import java.io.*;
public class Main {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
控制台输入输出
使用 Scanner
类从控制台读取输入,使用 System.out.println
进行输出。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.print("Enter your age: ");
int age = scanner.nextInt();
System.out.println("Hello, " + name + ". You are " + age + " years old.");
}
}
常用 Java 技术介绍
Java 面向对象编程
Java 是一种面向对象的编程语言,支持封装、继承和多态等特性。
类和对象
类是创建对象的模板,对象是类的实例。
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("John Doe", 25);
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
}
}
封装
封装是将数据和操作数据的方法封装在一起,通过访问修饰符控制数据的访问。
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void deposit(double amount) {
this.balance += amount;
}
public void withdraw(double amount) {
if (amount > this.balance) {
throw new IllegalArgumentException("Insufficient funds");
}
this.balance -= amount;
}
public double getBalance() {
return this.balance;
}
}
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
System.out.println("Balance: " + account.getBalance());
}
}
继承
继承允许一个类继承另一个类的属性和方法,提高代码的复用性。
public class Animal {
public void eat() {
System.out.println("Animal is eating");
}
public void sleep() {
System.out.println("Animal is sleeping");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Dog is barking");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.sleep();
dog.bark();
}
}
多态
多态允许子类可以覆盖父类的方法,调用时根据实际对象类型决定调用哪个方法。
public class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("Dog is eating");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
animal.eat();
Dog dog = new Dog();
animal = dog;
animal.eat();
}
}
Java 集合框架
Java 集合框架提供了一套强大的数据结构和接口来处理对象的集合。
List
List
接口的实现类包括 ArrayList
和 LinkedList
,实现列表数据结构。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
System.out.println("List: " + list);
for (String fruit : list) {
System.out.println(fruit);
}
}
}
Set
Set
接口的实现类包括 HashSet
和 TreeSet
,实现集合数据结构,不允许重复元素。
import java.util.*;
public class Main {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Banana");
System.out.println("Set: " + set);
for (String fruit : set) {
System.out.println(fruit);
}
}
}
Map
Map
接口的实现类包括 HashMap
和 TreeMap
,实现映射数据结构,键值对存储。
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
System.out.println("Map: " + map);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
}
}
Java 异常处理
Java 异常处理机制允许程序在发生异常时进行错误处理,而不是直接终止程序。
异常分类
异常可以分为 Checked Exception
和 Unchecked Exception
。
public class Main {
public static void main(String[] args) {
try {
// 可能产生异常的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
// 处理异常
System.out.println("Division by zero error: " + e.getMessage());
} finally {
// 无论是否发生异常都会执行的代码
System.out.println("Finally block executed.");
}
}
}
自定义异常
可以创建自定义异常类,继承 Exception
或 RuntimeException
类。
public class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}
public class Main {
public static void main(String[] args) {
try {
throw new CustomException("Custom exception occurred.");
} catch (CustomException e) {
System.out.println("Custom exception: " + e.getMessage());
} finally {
System.out.println("Finally block executed.");
}
}
}
简历项目需求分析
简历项目功能概述
简历项目是一个简单的 Web 应用,用于创建和展示个人信息。主要功能包括:
- 创建简历:用户可以输入姓名、联系方式、教育背景、工作经验等内容。
- 保存简历:将填写的信息保存到数据库中。
- 展示简历:通过 Web 页面展示简历内容,包括基本信息、教育背景、工作经验等。
- 编辑简历:用户可以编辑已保存的简历信息。
简历项目界面设计
简历项目的界面设计应简洁明了,易于操作。
前端设计
- 登录页面:简单的登录表单,用户输入用户名和密码进行登录。
- 创建简历页面:用户输入基本信息、教育经历和工作经验。
- 展示简历页面:展示用户填写的简历内容。
- 编辑简历页面:用户可以修改已保存的简历信息。
后端设计
- 用户管理:注册、登录、权限管理。
- 简历管理:创建、保存、展示、编辑简历信息。
- 数据库操作:存储用户信息和简历内容。
简历项目数据库设计
简历项目需要一个数据库来存储用户信息和简历内容。
数据库表结构
- 用户表 (
users
): 存储用户信息。id
: 用户唯一标识符username
: 用户名password
: 密码email
: 电子邮件
- 简历表 (
resumes
): 存储简历信息。id
: 唯一标识符user_id
: 用户 ID,关联用户表name
: 姓名contact
: 联系方式education
: 教育经历experience
: 工作经验created_at
: 创建时间updated_at
: 更新时间
数据库表示例代码
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE resumes (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
contact VARCHAR(255) NOT NULL,
education TEXT,
experience TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
简历项目开发步骤
环境搭建与工具准备
在开始开发简历项目之前,需要搭建开发环境并准备必要的工具。
-
安装 JDK:
- 下载并安装 JDK,确保安装路径正确,并将 JDK 的 bin 目录添加到系统环境变量 PATH 中。
-
安装数据库:
- 安装 MySQL 或 PostgreSQL,创建数据库和表。
-
安装并配置 Servlet 容器:
- 下载并安装 Tomcat 或 Jetty,配置好服务器路径。
- 安装前端开发工具:
- 使用 HTML、CSS 和 JavaScript 编写前端页面。
- 可以使用前端框架如 Bootstrap 或 Vue.js 加速开发。
创建项目结构
简历项目的目录结构如下:
resume-project
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── resume
│ │ │ ├── controller
│ │ │ ├── model
│ │ │ ├── repository
│ │ │ └── ResumeApplication.java
│ │ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── com
│ └── resume
│ └── ResumeApplicationTest.java
├── pom.xml
└── .gitignore
创建 Maven 项目
使用 Maven 创建一个新的 Java Web 项目。
<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.resume</groupId>
<artifactId>resume-project</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
实现简历信息输入功能
简历信息输入功能是用户创建简历的重要步骤。
创建模型类
创建 User
和 Resume
模型类。
package com.resume.model;
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String email;
// Getters and Setters
}
@Entity
@Table(name = "resumes")
public class Resume {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
private String name;
private String contact;
private String education;
private String experience;
// Getters and Setters
}
创建控制器
创建 ResumeController
控制器类。
package com.resume.controller;
import com.resume.model.Resume;
import com.resume.repository.ResumeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class ResumeController {
@Autowired
private ResumeRepository resumeRepository;
@GetMapping("/create")
public String showCreateForm(Model model) {
model.addAttribute("resume", new Resume());
return "create-resume";
}
@PostMapping("/create")
public String createResume(@ModelAttribute Resume resume) {
resumeRepository.save(resume);
return "redirect:/";
}
}
创建视图
创建 Thymeleaf 视图模板 create-resume.html
。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Create Resume</title>
</head>
<body>
<form th:action="@{/create}" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required />
<label for="contact">Contact:</label>
<input type="text" id="contact" name="contact" required />
<label for="education">Education:</label>
<textarea id="education" name="education" rows="4" cols="50" required></textarea>
<label for="experience">Experience:</label>
<textarea id="experience" name="experience" rows="4" cols="50" required></textarea>
<input type="submit" value="Create Resume" />
</form>
</body>
</html>
实现简历信息展示功能
简历信息展示功能用于显示用户创建的简历内容。
创建控制器
在 ResumeController
中添加展示简历的方法。
package com.resume.controller;
import com.resume.model.Resume;
import com.resume.repository.ResumeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class ResumeController {
@Autowired
private ResumeRepository resumeRepository;
@GetMapping("/create")
public String showCreateForm(Model model) {
model.addAttribute("resume", new Resume());
return "create-resume";
}
@PostMapping("/create")
public String createResume(@ModelAttribute Resume resume) {
resumeRepository.save(resume);
return "redirect:/";
}
@GetMapping("/")
public String showResumes(Model model) {
Iterable<Resume> resumes = resumeRepository.findAll();
model.addAttribute("resumes", resumes);
return "resumes";
}
}
创建视图
创建 Thymeleaf 视图模板 resumes.html
。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Resumes</title>
</head>
<body>
<h1>Resumes</h1>
<ul th:each="resume : ${resumes}">
<li>
<a th:href="@{'/edit/' + ${resume.id}}">Edit</a>
<a th:href="@{'/delete/' + ${resume.id}}" onclick="return confirm('Are you sure?')">Delete</a>
<p>Name: <span th:text="${resume.name}"></span></p>
<p>Contact: <span th:text="${resume.contact}"></span></p>
<p>Education: <span th:text="${resume.education}"></span></p>
<p>Experience: <span th:text="${resume.experience}"></span></p>
</li>
</ul>
<a href="/create">Create New Resume</a>
</body>
</html>
简历项目优化与测试
项目代码优化
优化代码结构,提高代码质量和可维护性。
重构代码
将业务逻辑部分从控制器中分离出来,提高代码的清晰度和可维护性。
package com.resume.service;
import com.resume.model.Resume;
import com.resume.repository.ResumeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ResumeService {
@Autowired
private ResumeRepository resumeRepository;
public void saveResume(Resume resume) {
resumeRepository.save(resume);
}
public Iterable<Resume> getAllResumes() {
return resumeRepository.findAll();
}
}
更新控制器
更新控制器以使用 ResumeService
。
package com.resume.controller;
import com.resume.model.Resume;
import com.resume.service.ResumeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
public class ResumeController {
@Autowired
private ResumeService resumeService;
@GetMapping("/create")
public String showCreateForm(Model model) {
model.addAttribute("resume", new Resume());
return "create-resume";
}
@PostMapping("/create")
public String createResume(@ModelAttribute Resume resume) {
resumeService.saveResume(resume);
return "redirect:/";
}
@GetMapping("/")
public String showResumes(Model model) {
model.addAttribute("resumes", resumeService.getAllResumes());
return "resumes";
}
}
界面美化
使用 CSS 和前端框架对界面进行美化。
添加样式
使用 Bootstrap 框架提升界面美观度。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Resumes</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1 class="text-center">Resumes</h1>
<div class="row">
<div class="col-md-4">
<a href="/create" class="btn btn-primary btn-block">Create New Resume</a>
</div>
</div>
<div class="row">
<ul th:each="resume : ${resumes}">
<li class="list-unstyled">
<a th:href="@{'/edit/' + ${resume.id}}" class="btn btn-secondary btn-sm">Edit</a>
<a th:href="@{'/delete/' + ${resume.id}}" onclick="return confirm('Are you sure?')" class="btn btn-danger btn-sm">Delete</a>
<p class="mt-2"><strong>Name:</strong> <span th:text="${resume.name}" /></p>
<p class="mt-2"><strong>Contact:</strong> <span th:text="${resume.contact}" /></p>
<p class="mt-2"><strong>Education:</strong> <span th:text="${resume.education}" /></p>
<p class="mt-2"><strong>Experience:</strong> <span th:text="${resume.experience}" /></p>
</li>
</ul>
</div>
</div>
</body>
</html>
编写测试用例
编写单元测试和集成测试确保代码质量。
单元测试
编写单元测试验证 ResumeService
的功能。
package com.resume.service;
import com.resume.model.Resume;
import com.resume.repository.ResumeRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
public class ResumeServiceTest {
@Mock
private ResumeRepository resumeRepository;
@InjectMocks
private ResumeService resumeService;
@Test
public void testSaveResume() {
Resume resume = new Resume();
resumeService.saveResume(resume);
verify(resumeRepository, times(1)).save(resume);
}
@Test
public void testGetAllResumes() {
Resume resume1 = new Resume();
Resume resume2 = new Resume();
when(resumeRepository.findAll()).thenReturn(Arrays.asList(resume1, resume2));
List<Resume> resumes = resumeService.getAllResumes();
assertEquals(2, resumes.size());
}
}
集成测试
编写集成测试验证控制器和数据库交互。
package com.resume.controller;
import com.resume.model.Resume;
import com.resume.repository.ResumeRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@ExtendWith(SpringRunner.class)
@WebMvcTest(controllers = ResumeController.class)
public class ResumeControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ResumeRepository resumeRepository;
@Test
public void testCreateResume() throws Exception {
Resume resume = new Resume();
when(resumeRepository.save(any(Resume.class))).thenReturn(resume);
mockMvc.perform(post("/create")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("name", "John Doe")
.param("contact", "john.doe@example.com")
.param("education", "Master's Degree")
.param("experience", "Software Engineer"))
.andExpect(status().is3xxRedirection());
}
@Test
public void testShowResumes() throws Exception {
Resume resume1 = new Resume();
Resume resume2 = new Resume();
when(resumeRepository.findAll()).thenReturn(Arrays.asList(resume1, resume2));
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("resumes"))
.andExpect(model().attribute("resumes", hasSize(2)));
}
}
运行测试并修复 Bug
运行测试用例并修复代码中的 Bug。
运行测试
在 IntelliJ IDEA 中右键点击测试用例运行测试。
修复 Bug
根据测试结果修复代码中的 Bug。
项目部署与分享项目打包与发布
将项目打包成 WAR 文件并部署到 Servlet 容器。
打包项目
使用 Maven 打包项目。
mvn clean package
部署到 Tomcat
将生成的 WAR 文件复制到 Tomcat 容器的 webapps
目录。
cp target/resume-project-1.0.0.war /path/to/tomcat/webapps/
启动 Tomcat 服务器,访问 http://localhost:8080/resume-project-1.0.0/
查看项目。
项目上传至 GitHub
将项目代码上传到 GitHub 仓库。
创建 GitHub 仓库
登录 GitHub 创建一个新的仓库。
连接本地仓库
在本地项目中初始化 Git 仓库。
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/username/resume-project.git
git push -u origin master
项目演示与分享
录制项目演示视频并分享到社交媒体或社区。
录制演示视频
使用屏幕录制工具录制项目演示视频。
分享到社交媒体
将演示视频分享到 LinkedIn、微博等社交媒体平台,吸引更多关注和反馈。
通过以上步骤,你可以完成一个完整的简历项目的开发、测试和部署。希望这篇文章对你有所帮助!
共同学习,写下你的评论
评论加载中...
作者其他优质文章