JavaWeb階段性學習總結

1.功能簡介

實現學生信息的簡單操作:分頁查看以及增刪改。

2.使用的基本框架

學生信息系統
用戶的請求由Jsp界面接受,然後轉發給具體的Servlet,功能實現由Service層實現,具備業務邏輯的數據操作,例如:要修改一個學生的信息則必須保證這個學生的信息已經存在,若不存在則進行添加,所以要先進行查詢操作。這些基本的數據操作由數據訪問層來完成並將具體結果依次向上返回到Servlet,將結果處理後再由Jsp展示

3.具體項目結構

在這裏插入圖片描述

4.代碼實現

在代碼註釋中有具體的邏輯描述

JavaBean

學生信息:

package org.studentinfo.entity;

public class Student {
	private int id;// 學生Id
	private String no;// 學號
	private String name;// 姓名
	private String address;// 家庭住址

	public Student(int id, String no, String name, String address) {
		super();
		this.id = id;
		this.no = no;
		this.name = name;
		this.address = address;
	}

	public Student(String no, String name, String address) {
		super();
		this.no = no;
		this.name = name;
		this.address = address;
	}

	public Student() {
		super();
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", no=" + no + ", name=" + name + ", address=" + address + "]";
	}

}

頁面信息:(用於分頁顯示)

package org.studentinfo.entity;

import java.util.List;

public class PageInfo {

	private int currentPage;// 當前頁面
	private int count;// 總數據數
	private int pageSize;// 當前頁面大小
	private int totalPage;// 總頁數
	private List<Student> students;// 當前頁面具體數據

	public PageInfo() {
	}
	public PageInfo(int currentPage, int count, int pageSize, List<Student> students) {
		super();
		this.currentPage = currentPage;
		this.count = count;
		this.pageSize = pageSize;
		this.students = students;
		this.totalPage = (this.count % this.pageSize == 0) ? (this.count / this.pageSize)
				: (this.count / this.pageSize + 1);
	}

	@Override
	public String toString() {
		return "PageInfo [當前頁:" + currentPage + ", 數據總數:" + count + ", 頁面大小:" + pageSize + ", 總頁數:" + totalPage
				+ "學生信息:" + students + "]";
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
		this.totalPage = (this.count % this.pageSize == 0) ? (this.count / this.pageSize)
				: (this.count / this.pageSize + 1);
	}


	public List<Student> getStudents() {
		return students;
	}

	public void setStudents(List<Student> students) {
		this.students = students;
	}

	public int getTotalPage() {
		return totalPage;
	}

}

數據庫操作工具類

將JDBC的重複操作抽象出來形成一個工具類,實現泛化的查詢與修改操作
在這個類中將數據庫連接固定了下來,也可以以get、set方式將這個具體連接信息作爲參數傳入。
另外,在加載驅動前要導入依賴的jar包
在這裏插入圖片描述
這裏使用的是MySQL數據庫,不同的數據庫依賴的驅動jar包不同

package org.studentinfo.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBUtil {
	private static final String URL = "jdbc:mysql://localhost:3306/test?serverTimezone=GMT";// 數據庫位置,位置信息必須添加!
	private static final String USERNAME = "root";// 用戶名
	private static final String PASSWORD = "helloworld";// 用戶密碼
	public static Connection connection = null;
	public static PreparedStatement pstm = null;
	public static ResultSet rs = null;

	public static void createConnection() throws ClassNotFoundException, SQLException {// 創建連接
		Class.forName("com.mysql.cj.jdbc.Driver");
		connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
	}

	public static void createPreparedStatement(String sql, Object[] param) throws SQLException {// 替換佔位符
		pstm = connection.prepareStatement(sql);
		if (param != null) {
			for (int i = 0; i < param.length; i++) {
				pstm.setObject(i + 1, param[i]);
			}
		}
	}

	public static void destory() throws SQLException {// 回收資源
	/*
	 *將Connection、PreparedStatement、ResultSet做爲工具類的屬性。也可以傳入參數進行回收
	*/
		if (rs != null)
			rs.close();
		if (pstm != null)
			pstm.close();
		if (connection != null)
			connection.close();
	}

	public static ResultSet query(String sql, Object[] param) {// 通用查詢
		try {
			createConnection();// 創建連接
			createPreparedStatement(sql, param);// 填充sql語句
			rs = pstm.executeQuery();// 執行操作
			return rs;
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		}
		// 因爲要返回具體結果集,所以不能在工具類內部進行資源回收
		return rs;
	}

	public static boolean update(String sql, Object[] param) throws SQLException {// 通用修改
		boolean flag = false;
		try {
			createConnection();
			createPreparedStatement(sql, param);
			if (pstm.executeUpdate() > 0) {// 修改成功返回true
				flag = true;
			} else {
				flag = false;
			}
		} catch (ClassNotFoundException | SQLException e) {
			e.printStackTrace();
		} finally {
		// 修改操作只返回結果表示不使用結果集,所以可以在此處直接進行回收
			destory();
		}
		return flag;
	}
}

Jsp頁面

首頁:
截圖展示:
在這裏插入圖片描述
用戶進入頁面第一次默認訪問首頁。點擊刪除鏈接可以直接刪除對應的學生信息,並重新加載首頁。點擊增加按鈕,進入學生信息增加頁面,輸入具體學生信息,進行添加。點擊修改按鈕將根據學生學號進行修改。點擊下一頁或上一頁進行分頁跳轉。點擊首頁或尾頁直接回到首頁或尾頁。點擊學號可以查看更多該學生信息

<body>
	<%
		if (request.getAttribute("pageinfo") == null) {
		request.getRequestDispatcher("QueryStudentInfoByPageServlet").forward(request, response);
		request.setAttribute("error", "");
		if (request.getAttribute("error").equals("操作失敗!")) {
			out.print("操作失敗!");
		}
	}
	%>
	<table border="1px">
		<tr>
			<th>學號</th>
			<th>姓名</th>
			<th>點擊對應鏈接刪除</th>
		</tr>
		<%
			PageInfo pageinfo = (PageInfo) request.getAttribute("pageinfo");
		ArrayList<Student> students = (ArrayList<Student>) pageinfo.getStudents();
		for (Student student : students) {
		%>
		<tr>
			<td><a
				href='QueryStudentInfoBySnoServlet?sno=<%=student.getNo()%>'> <%=student.getNo()%>
			</a></td>
			<td><%=student.getName()%></td>
			<td><a href='DeleteStudentInfoServlet?sno=<%=student.getNo()%>'>
					刪除 </a></td>
		</tr>
		<%
			}
		%>
		<tr>
			<td>
				<form action="addstudent.jsp">
					<input type="submit" value="增加學生信息">
				</form>
			</td>
			<td>
				<form action="updatestudent.jsp">
					<input type="submit" value="修改學生信息">
				</form>
			</td>
		</tr>
	</table>
	<a href='QueryStudentInfoByPageServlet'>首頁</a>
	<a
		href='QueryStudentInfoByPageServlet?currentPage=<%=pageinfo.getCurrentPage() - 1%>'>上一頁</a>
	<a
		href='QueryStudentInfoByPageServlet?currentPage=<%=pageinfo.getCurrentPage() + 1%>'>下一頁</a>
	<a
		href='QueryStudentInfoByPageServlet?currentPage=<%=pageinfo.getTotalPage()%>'>尾頁</a>
</body>

學生具體信息頁面:不能直接訪問該頁面,因爲沒有學生具體信息的來源。
在這裏插入圖片描述

<%@page import="org.studentinfo.entity.PageInfo"%>
<%@page import="org.studentinfo.entity.Student"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
	    //PageInfo pageinfo = (PageInfo) request.getAttribute("pageinfo");
		Student student = (Student) request.getAttribute("student");
	%>
	<table border="1px">
		<tr>
			<th>學號</th>
			<th>姓名</th>
			<th>地址</th>
		</tr>
		<tr>
			<td><%=student.getNo()%></td>
			<td><%=student.getName()%></td>
			<td><%=student.getAddress()%></td>
		</tr>
		<tr>
			<td>
				<form action="QueryStudentInfoByPageServlet">
					<input type="submit" value="返回主頁">
				</form>
			</td>
		</tr>
	</table>
</body>
</html>

增加學生信息頁面:
在這裏插入圖片描述

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="AddStudentInfoServlet">
		<table>
			<tr>
				<td>id</td>
				<td><input type="text" name=id /></td>
			</tr>
			<tr>
				<td>學號</td>
				<td><input type="text" name=sno /></td>
			</tr>
			<tr>
				<td>姓名</td>
				<td><input type="text" name=sname /></td>
			</tr>
			<tr>
				<td>住址</td>
				<td><input type="text" name=saddress /></td>
			</tr>
			<tr>
				<td><input type="submit" value="確認增加" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

修改學生信息頁面:
在這裏插入圖片描述

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="UpdateStudentInfoServlet">
		<table>
			<tr>
				<td>原學號</td>
				<td><input type="text" name=sno /></td>
			</tr>
			<tr>
				<td>id</td>
				<td><input type="text" name=id /></td>
			</tr>
			<tr>
				<td>新學號</td>
				<td><input type="text" name=no /></td>
			</tr>
			<tr>
				<td>姓名</td>
				<td><input type="text" name=sname /></td>
			</tr>
			<tr>
				<td>住址</td>
				<td><input type="text" name=saddress /></td>
			</tr>
			<tr>
				<td><input type="submit" value="確認修改" /></td>
			</tr>
		</table>
	</form>
</body>
</html>

Servlet

每一個頁面操作對應一個Servlet(主要是doGet()與doPost()方法)
增加:

@WebServlet("/AddStudentInfoServlet")
public class AddStudentInfoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public AddStudentInfoServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StudentInfoService dao = new StudentInfoService();
		int id = Integer.parseInt(request.getParameter("id"));
		String sno = request.getParameter("sno");
		String sname = request.getParameter("sname");
		String saddress = request.getParameter("saddress");
		Student student = new Student(id,sno,sname,saddress);
		if(!dao.addStudent(student)) {
			request.setAttribute("error", "操作失敗!");
		}else {
			request.getRequestDispatcher("QueryStudentInfoByPageServlet").forward(request, response);
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

刪除:

@WebServlet("/DeleteStudentInfoServlet")
public class DeleteStudentInfoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public DeleteStudentInfoServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StudentInfoService dao = new StudentInfoService();
		String sno = request.getParameter("sno");
		if(!dao.deleteStudent(sno)) {
			request.setAttribute("error", "操作失敗!");
		}else {
			request.getRequestDispatcher("QueryStudentInfoByPageServlet").forward(request, response);
		}
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

修改:

@WebServlet("/UpdateStudentInfoServlet")
public class UpdateStudentInfoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public UpdateStudentInfoServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StudentInfoService dao = new StudentInfoService();
		int id = Integer.parseInt(request.getParameter("id"));
		String sno = request.getParameter("sno");
		String no = request.getParameter("no");
		String sname = request.getParameter("sname");
		String saddress = request.getParameter("saddress");
		Student student = new Student(id, no, sname, saddress);
//		System.out.println(student);
		boolean flag = dao.updateStudent(sno, student);
		if (!flag) {
			request.setAttribute("error", "操作失敗!");
		}
		request.getRequestDispatcher("QueryStudentInfoByPageServlet").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

查詢所有:

@WebServlet("/QueryAllStudentsServlet")
public class QueryAllStudentsServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public QueryAllStudentsServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StudentInfoService dao = new StudentInfoService();
		List<Student> students = dao.queryAllStudent();
		if (students != null) {
			request.setAttribute("students", students);
		} else {
			// System.out.println("結果集爲空 !");
			request.setAttribute("error", "操作失敗!");
		}
		request.getRequestDispatcher("index.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

查詢單個:

@WebServlet("/QueryStudentInfoBySnoServlet")
public class QueryStudentInfoBySnoServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public QueryStudentInfoBySnoServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String sno = request.getParameter("sno");
		StudentInfoService dao = new StudentInfoService();
		Student student = dao.queryBySno(sno);
		if (student != null) {
			request.setAttribute("student", student);
		} else {
			request.setAttribute("error", "查詢失敗");
		}
		request.getRequestDispatcher("showstudent.jsp").forward(request, response);// 涉及到數據,請求轉發到個人信息顯示頁面
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

分頁查詢:
步驟:
1.數據總數 (查詢數據庫獲得)
2.頁面大小(頁面容量,每頁顯示的數據條數,由用戶自定義)
3.總頁數 (自動計算) 總頁數= 數據總數 % 頁面大小==0 ?數據總數 /頁面大小:數據總數 /頁面大小 + 1;
注意:自動計算的時機:當數據總數和頁面大小都被賦值以後,自動計算總頁數。
4.當前頁碼(用戶自定義)
5.實體類對象集合(當前頁的數據集合):依賴於數據庫
所以將這些包裝成一個Page類JavaBean

@WebServlet("/QueryStudentInfoByPageServlet")
public class QueryStudentInfoByPageServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public QueryStudentInfoByPageServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StudentInfoService dao = new StudentInfoService();
		PageInfo pageinfo = new PageInfo();
		int count = dao.getCount();// 數據總數
		pageinfo.setCount(count);
		int pageSize = 3;// 當前頁面大小,可以寫死,也可以通過用戶請求設置
		pageinfo.setPageSize(pageSize);
		int currentPage = 1;
		if (request.getParameter("currentPage") != null) {// 第一次請求時默認訪問首頁
			currentPage = Integer.parseInt(request.getParameter("currentPage"));// 當前頁面
		}
		if (currentPage > pageinfo.getTotalPage() || currentPage < 1) {// 當頁碼太大時自動回滾到首頁,太小時留在首頁
			currentPage = 1;
		}
//		System.out.println("當前傳遞到來的當前頁面爲:"+ currentPage);
		List<Student> students = dao.queryByPage(currentPage, pageSize);// 具體數據集合
		pageinfo.setCurrentPage(currentPage);
		pageinfo.setStudents(students);
		if (students != null) {
			request.setAttribute("pageinfo", pageinfo);
		} else {
			request.setAttribute("error", "操作失敗!");
		}
		request.getRequestDispatcher("index2.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

Service層

實現業務邏輯,主要負責基本操作的組織。

package org.studentinfo.service;

import java.util.List;

import org.studentinfo.dao.StudentInfoDao;
import org.studentinfo.entity.Student;

public class StudentInfoService {
	
	private StudentInfoDao dao = null;

	public StudentInfoService() {
		super();
		dao = new StudentInfoDao();
	}
	public Student queryBySno(String sno) {
		return dao.queryBySno(sno);
	}
	public List<Student> queryAllStudent() {
		return dao.queryAllStudent();
	}
	public boolean addStudent(Student student) {//增加
		if(dao.queryBySno(student.getNo()) != null) {
			return false;
		}else {
			dao.addStudent(student);
			return true;
		}
	}
	public boolean deleteStudent(String sno) {//刪除
		if(dao.queryBySno(sno) != null) {
			dao.deleteStudent(sno);
			return true;
		}else {
			return false;
		}
	}
	public boolean updateStudent(String sno,Student student) {//修改
		if(dao.queryBySno(sno) != null) {
			//System.out.println(student);
			dao.updateStudent(sno, student);
			return true;
		}else {
			return false;
		}
	}
	public int getCount() {
		return dao.getCount();
	}
	public List<Student> queryByPage(int currentPage, int pageSize) {
		return dao.queryByPage(currentPage, pageSize);
	}
}

Dao層

數據訪問層,直接對數據庫進行操作。將SQL語句和補齊佔位符數組傳入。

package org.studentinfo.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.studentinfo.entity.Student;
import org.studentinfo.util.DBUtil;

public class StudentInfoDao {
	private ResultSet rs = null;
	private Student student = null;
	private List<Student> students = null;

	// 根據學號查單個學生
	public Student queryBySno(String sno) {
		try {
			String sql = "SELECT sno,sname,saddress FROM studeninfo WHERE sno = ? ";
			Object[] param = { sno };
			rs = DBUtil.query(sql, param);
			if (rs.next()) {
				String no = (String) (rs.getObject("sno"));
				String name = (String) (rs.getObject("sname"));
				String address = (String) (rs.getObject("saddress"));
				student = new Student(no, name, address);
			} else {
				return null;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return student;

	}

	// 查詢所有學生信息
	public List<Student> queryAllStudent() {
		students = new ArrayList<Student>();
		try {
			String sql = "SELECT id,sno,sname,saddress FROM studeninfo ";
			Object[] param = null;
			rs = DBUtil.query(sql, param);
			while (rs.next()) {
				int id = (int) (rs.getObject("id"));
				String no = (String) (rs.getObject("sno"));
				String name = (String) (rs.getObject("sname"));
				String address = (String) (rs.getObject("saddress"));
				student = new Student(id, no, name, address);
				students.add(student);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return students;
	}

	// 增加學生信息
	public boolean addStudent(Student student) {
		boolean flag = false;
		try {
			String sql = "INSERT INTO studeninfo VALUES ( ?, ? , ? , ? ) ";
			Object[] param = { student.getId(), student.getNo(), student.getName(), student.getAddress() };
			flag = DBUtil.update(sql, param);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return flag;
	}

	// 刪除學生信息
	public boolean deleteStudent(String sno) {
		boolean flag = false;
		try {
			String sql = "DELETE FROM studeninfo WHERE sno = ?";
			Object[] param = { sno };
			flag = DBUtil.update(sql, param);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return flag;
	}

	// 修改學生信息
	public boolean updateStudent(String sno, Student student) {
		boolean flag = false;
		try {
			String sql = "UPDATE studeninfo SET id = ? , sno = ? , sname = ? , saddress = ? WHERE sno = ? ";
			Object[] param = { student.getId(), student.getNo(), student.getName(), student.getAddress(), sno };
			flag = DBUtil.update(sql, param);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return flag;
	}

	// 查詢列表大小
	public int getCount() {
		String sql = "SELECT count(1) from studeninfo";
		int count = -1;
		try {
			rs = DBUtil.query(sql, null);
			if(rs.next()) {
				count = rs.getInt(1);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return count;
	}

	public List<Student> queryByPage(int currentPage, int pageSize) {
		students = new ArrayList<Student>();
		try {
			String sql = "SELECT * FROM studeninfo ORDER BY id LIMIT ?, ? ";
			Object[] param = { (currentPage - 1) * pageSize, pageSize };
			rs = DBUtil.query(sql, param);
			while (rs.next()) {
				int id = (int) (rs.getObject("id"));
				String no = (String) (rs.getObject("sno"));
				String name = (String) (rs.getObject("sname"));
				String address = (String) (rs.getObject("saddress"));
				student = new Student(id, no, name, address);
				students.add(student);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				DBUtil.destory();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return students;
	}
}

5.具體數據庫示例

在這裏插入圖片描述

6.優化改進方向

(1)增加登錄界面,使用攔截器進行登錄驗證與信息篩選
(2)設置監聽器統計網站訪問人數
(3)優化界面顯示
(4)在用戶刪除具體信息時應設置提示語句,防止誤操作
(5)用戶權限分級
(6)設置文件上傳與下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章