170
社区成员
Course for This Assignment | 2401_MU_SE_EE308 |
---|---|
Group Students | Huang Xingcheng Guo Yongzhen |
First Student ID | FZU:832201123 MU:22125469 |
Second Student ID | FZU:832202122 MU:22124594 |
Assignment Requirements | Extreme Programming: Improve a front-end and back-end separated contact |
Objectives of This Assignment | Exercise extreme programming ability and learn the basic knowledge of software development |
Other References | https://developer.aliyun.com/article/850913 |
1.1 Task Description
The Extreme Programming assignment for Software Engineering involves enhancing the functionality of a front-end and back-end separated address book system. We were required to complete a series of programming tasks within a strict two-day timeline. This assignment emphasizes teamwork, the application of theoretical knowledge, and the development of a reliable system with efficient front-end and back-end integration. The primary functionalities to be implemented include:
1.2 Git Repository Link and Coding Standards Link
This blog post provides an in-depth overview of our project, including the final product, system architecture, and the development process. The complete source code can be found in our repository. Sensitive information, such as database credentials, has been excluded from the public repository.
Git Repository Link:https://github.com/snakeguoguo/address-book.git
Address Book GitHub Repository
The back-end implementation is located in the root directory, while the front-end resources are organized under the templates
and static
folders.
Coding Standards:
We adhered to the PEP 8 guidelines for Python code and followed best practices for HTML, CSS, and JavaScript development. The project structure was designed to ensure readability and maintainability.
Coding Standards Link and Useful Link:
We recorded the estimated and actual time to develop each module of the program in the PSP sheet.
Xingcheng Huang
Modules | Task Description | Estimated Time | Actual Time |
---|---|---|---|
Group Discussion and Demand Analysis | Determine the requirements of the web page and the functions that can be achieved | 1 hour | 1 hour |
Knowledge Learning | Learning about Excel Import and Export | 1 hours | 2 hours |
Backend Development | Create a Spring Boot application and write an interface | 3 hours | 5 hours |
Backend Test | Test whether the web page meets expectations | 2 hour | 2 hours |
Deploy | Deploy the application to the server (Alibaba Cloud) | 2 hours | 1 hours |
Total | 9 hours | 11 hours |
Yongzhen Guo
Modules | Task Description | Estimated Time | Actual Time |
---|---|---|---|
Group Discussion and Demand Analysis | Determine the requirements of the web page and the functions that can be achieved | 1 hour | 1 hour |
Knowledge Learning | Learning about Excel Import and Export | 1 hours | 2 hours |
Front-end Development | Page design, front-end development using JS | 2 hours | 3 hours |
Front-end Test | Test whether the web page meets expectations | 1 hour | 1.5 hours |
Front-end and Back-end Integration Testing | Test whether the front-end and back-end integration works as expected | 2 hours | 3 hours |
Total | 7 hours | 10.5 hours |
Member Name | Contribution (%) |
---|---|
Xingcheng Huang | 85 |
Yongzhen Guo | 15 |
3.1 Project Background
The Address Book Management System aims to provide users with a convenient platform to manage contact information using a modern front-end and back-end separation architecture. The system allows users to display contact information on a webpage and perform intuitive operations such as adding, editing, deleting, and querying contact details.
3.2 Project Significance
This project simplifies the process of managing contact information through a user-friendly web interface. By implementing a front-end and back-end separated architecture, the system enhances responsiveness and user experience while improving maintainability and scalability for future development.
3.3 Design Concept and Technology Selection
When designing the address book application, the following functional modules and technologies were considered:
Front-end and Back-end Separation:
Contact Management with In-Memory and Persistent Data:
Data Interaction:
Responsive Design:
3.4 Implementation Process
1. Environment Setup
Development Environment Configuration:
bash
复制代码
pip install flask pandas
Data Storage:
contacts.py
.2. Functional Modules
Function 1: User Interface
When users visit the system, they will see a clean and intuitive interface.
The page design includes a list of contacts and buttons for adding, deleting, and editing contact details.
Example interface screenshot:
Function 2: Bookmark Contacts
is_bookmarked
attribute to the contact model in the back end.POST
request from the front end.Function 3: Multiple Contact Methods
Function 4: Import and Export
pandas
library in the back end to process Excel files.Function 5: Deployment
When you visit http://127.0.0.1:5000, you will see this interface:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Address Book</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<h1>Address Book</h1>
<!-- 输入表单 -->
<div class="form-container">
<form id="addContactForm">
<label>姓名:</label>
<input type="text" id="contact_name" placeholder="姓名" required>
<label>学号:</label>
<input type="text" id="contact_id" placeholder="学号">
<label>地址:</label>
<input type="text" id="contact_address" placeholder="地址">
<label>邮箱:</label>
<input type="email" id="contact_email" placeholder="邮箱">
<label>电话:</label>
<input type="text" id="contact_phone" placeholder="电话">
<label>备注:</label>
<input type="text" id="contact_notes" placeholder="备注">
<button type="submit" class="btn btn-primary">添加联系人</button>
</form>
</div>
<!-- 联系人表格 -->
<table class="contact-table">
<thead>
<tr>
<th>姓名</th>
<th>电话</th>
<th>学号</th>
<th>邮箱</th>
<th>地址</th>
<th>备注</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for contact in contacts %}
<tr>
<td>{{ contact.name }}</td>
<td>{{ contact.phone }}</td>
<td>{{ contact.id }}</td>
<td>{{ contact.email }}</td>
<td>{{ contact.address }}</td>
<td>{{ contact.notes }}</td>
<td>
<button onclick="editContact({{ loop.index0 }})" class="btn btn-edit">编辑</button>
<button onclick="deleteContact({{ loop.index0 }})" class="btn btn-delete">删除</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
// 添加联系人
document.getElementById('addContactForm').addEventListener('submit', function(event) {
event.preventDefault();
const name = document.getElementById('contact_name').value;
const phone = document.getElementById('contact_phone').value;
const id = document.getElementById('contact_id').value;
const email = document.getElementById('contact_email').value;
const address = document.getElementById('contact_address').value;
const notes = document.getElementById('contact_notes').value;
fetch('/add_contact', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name,
phone: phone,
id: id,
email: email,
address: address,
notes: notes
}),
}).then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Contact added!");
location.reload(); // 刷新页面
} else {
alert(data.message);
}
});
});
// 删除联系人
function deleteContact(contactId) {
if (confirm("确定要删除这个联系人吗?")) {
fetch(`/delete_contact/${contactId}`, {
method: 'DELETE',
}).then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Contact deleted!");
location.reload();
} else {
alert(data.message);
}
});
}
}
// 编辑联系人
function editContact(contactId) {
const newName = prompt("请输入新的姓名:");
const newPhone = prompt("请输入新的电话:");
const newId = prompt("请输入新的学号:");
const newEmail = prompt("请输入新的邮箱:");
const newAddress = prompt("请输入新的地址:");
const newNotes = prompt("请输入新的备注:");
fetch(`/edit_contact/${contactId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: newName,
phone: newPhone,
id: newId,
email: newEmail,
address: newAddress,
notes: newNotes
}),
}).then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Contact updated!");
location.reload();
} else {
alert(data.message);
}
});
}
</script>
</body>
</html>
<body>
<h1>Address Book</h1>
<!-- 上传文件表单 -->
<div class="form-container">
<form id="importForm" enctype="multipart/form-data">
<label for="fileInput">导入联系人:</label>
<input type="file" id="fileInput" name="file" accept=".xlsx">
<button type="submit" class="btn btn-primary">导入</button>
</form>
<button onclick="exportContacts()" class="btn btn-secondary">导出联系人</button>
</div>
<script>
// 导入联系人
document.getElementById('importForm').addEventListener('submit', function (event) {
event.preventDefault();
const fileInput = document.getElementById('fileInput');
const formData = new FormData();
formData.append('file', fileInput.files[0]);
fetch('/import', {
method: 'POST',
body: formData
}).then(response => response.json())
.then(data => {
if (data.status === "success") {
alert("Contacts imported successfully!");
location.reload();
} else {
alert("Error: " + data.message);
}
}).catch(error => console.error('Error:', error));
});
// 导出联系人
function exportContacts() {
window.location.href = '/export';
}
</script>
</body>
from flask import Flask, render_template, request, jsonify
import pandas as pd
from contacts import Contact
app = Flask(__name__)
# 初始化联系人列表
contacts = []
@app.route('/')
def index():
return render_template('index.html', contacts=contacts)
@app.route('/add_contact', methods=['POST'])
def add_contact():
data = request.get_json()
name = data.get('name')
phone = data.get('phone')
student_id = data.get('id')
email = data.get('email')
address = data.get('address')
notes = data.get('notes')
if not name:
return jsonify({"status": "error", "message": "Name is required"}), 400
new_contact = Contact(name=name, phone=phone, id=student_id, email=email, address=address, notes=notes)
contacts.append(new_contact)
return jsonify({"status": "success", "contact": new_contact.__dict__})
@app.route('/delete_contact/<int:contact_id>', methods=['DELETE'])
def delete_contact(contact_id):
if 0 <= contact_id < len(contacts):
removed_contact = contacts.pop(contact_id)
return jsonify({"status": "success", "removed_contact": removed_contact.__dict__})
else:
return jsonify({"status": "error", "message": "Contact not found"})
@app.route('/edit_contact/<int:contact_id>', methods=['PUT'])
def edit_contact(contact_id):
if 0 <= contact_id < len(contacts):
data = request.get_json()
contact = contacts[contact_id]
contact.name = data.get('name', contact.name)
contact.phone = data.get('phone', contact.phone)
contact.id = data.get('id', contact.id)
contact.email = data.get('email', contact.email)
contact.address = data.get('address', contact.address)
contact.notes = data.get('notes', contact.notes)
return jsonify({"status": "success", "updated_contact": contact.__dict__})
else:
return jsonify({"status": "error", "message": "Contact not found"})
if __name__ == '__main__':
app.run(debug=True)
import os
from flask import Flask, render_template, request, jsonify, send_file
import pandas as pd
from contacts import Contact
app = Flask(__name__)
# 初始化联系人列表
contacts = []
@app.route('/')
def index():
return render_template('index.html', contacts=contacts)
@app.route('/add_contact', methods=['POST'])
def add_contact():
data = request.get_json()
name = data.get('name')
phone = data.get('phone')
student_id = data.get('id')
email = data.get('email')
address = data.get('address')
notes = data.get('notes')
if not name:
return jsonify({"status": "error", "message": "Name is required"}), 400
new_contact = Contact(name=name, phone=phone, id=student_id, email=email, address=address, notes=notes)
contacts.append(new_contact)
return jsonify({"status": "success", "contact": new_contact.__dict__})
@app.route('/export', methods=['GET'])
def export_contacts():
# 将联系人列表导出为 Excel 文件
data = [{
"Name": contact.name,
"Phone": contact.phone,
"ID": contact.id,
"Email": contact.email,
"Address": contact.address,
"Notes": contact.notes
} for contact in contacts]
df = pd.DataFrame(data)
file_path = "contacts_export.xlsx"
df.to_excel(file_path, index=False)
return send_file(file_path, as_attachment=True)
@app.route('/import', methods=['POST'])
def import_contacts():
# 从 Excel 文件导入联系人
if 'file' not in request.files:
return jsonify({"status": "error", "message": "No file provided"}), 400
file = request.files['file']
try:
df = pd.read_excel(file)
for _, row in df.iterrows():
contact = Contact(
name=row.get('Name'),
phone=row.get('Phone'),
id=row.get('ID'),
email=row.get('Email'),
address=row.get('Address'),
notes=row.get('Notes')
)
contacts.append(contact)
return jsonify({"status": "success", "message": "Contacts imported successfully"})
except Exception as e:
return jsonify({"status": "error", "message": str(e)}), 500
While working on the project, we encountered several technical challenges. Here’s a breakdown of the key issues and how we addressed them:
5.1 Challenges for Team Member 1 (Backend Development)
Problem:
While implementing the Excel Import and Export functionalities, there were frequent errors during the file reading process. Specifically, the system failed to correctly parse and store the data from the uploaded Excel file.
Solution:
To debug, I added a try-except
block in the relevant part of the code to trace the root cause of the issue. It turned out the problem was due to inconsistent column headers in the imported Excel file. After aligning the headers in the file with the system’s expected format, the import functionality worked perfectly. The export functionality was also optimized using the pandas
library to ensure proper formatting.
5.2 Challenges for Team Member 2 (Frontend Development)
Problem:
While implementing the “Bookmark Contacts” feature, I faced challenges in ensuring seamless integration between the front-end button and back-end API. Additionally, there were errors in updating the bookmark status on the webpage after interacting with the server.
Solution:
The issue was resolved by thoroughly debugging the Fetch
API calls and correcting the endpoint URLs. Furthermore, I worked closely with the backend developer to ensure the API responses were in the correct format. Testing was carried out using Postman to verify the data exchange between the front end and back end. This collaborative effort led to the successful implementation of the Favorites feature.
5.3 Conclusion
This project demonstrated the value of teamwork and collaborative problem-solving. Each team member brought unique skills and perspectives to the table, contributing to the completion of a well-functioning system. Through effective task division and persistence in overcoming challenges, we were able to achieve our project goals.
Looking ahead, we aim to further improve our workflow by incorporating lessons learned from this project, such as conducting more thorough initial testing and improving communication between team members during development.
Through this assignment, we gained valuable insights and practical experience. Here are the key takeaways:
6.1 Collaborative Development
We enhanced our teamwork skills by effectively coordinating tasks, sharing progress, and resolving conflicts together.
6.2 Knowledge Application
This project bridged the gap between theoretical knowledge and practical implementation, allowing us to apply concepts from software engineering to real-world coding challenges.
6.3 Technical Proficiency
Backend Development:
We gained hands-on experience with Python Flask, learning to design RESTful APIs and handle data operations such as Excel import/export.
Frontend Development:
By working with HTML, CSS, and JavaScript, we developed skills in creating user-friendly interfaces and implementing interactive features. Debugging tools like Postman and browser developer tools proved invaluable during this process.
6.4 Time Management
Working under tight deadlines required us to carefully plan and prioritize our tasks. This helped improve our ability to deliver quality results within a limited timeframe.
We are sincerely grateful to our professor and teaching assistants for their guidance and support throughout this project. Their feedback and encouragement have been invaluable to our learning journey.
Thank you for reading about our experience! Please feel free to share any suggestions or feedback to help us improve.