From 9d5d22c813e0d8b494e94674f346d64a7460a44f Mon Sep 17 00:00:00 2001
From: liyansheng <1761724207@qq.com>
Date: Fri, 20 Dec 2024 22:35:13 +0800
Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=88=9D=E6=AD=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 38 ++
.idea/.gitignore | 3 +
.idea/dbnavigator.xml | 402 ++++++++++++++++++
.idea/encodings.xml | 7 +
.idea/misc.xml | 14 +
.idea/vcs.xml | 6 +
.../JSP_Servlet_Template/conf/server.xml | 31 ++
.../JSP_Servlet_Template/conf/web.xml | 50 +++
.smarttomcat/Jsp_register/conf/server.xml | 31 ++
.smarttomcat/Jsp_register/conf/web.xml | 50 +++
pom.xml | 92 ++++
readme.md | 7 +
.../example/controller/RegisterServlet.java | 48 +++
.../example/controller/UserListServlet.java | 119 ++++++
src/main/java/example/dao/UserDao.java | 43 ++
src/main/java/example/model/User.java | 42 ++
src/main/java/example/utils/DBUtil.java | 50 +++
src/main/java/example/utils/DBUtils.java | 24 ++
src/main/webapp/WEB-INF/web.xml | 6 +
src/main/webapp/index.jsp | 9 +
src/main/webapp/register.jsp | 18 +
src/main/webapp/userList.jsp | 38 ++
22 files changed, 1128 insertions(+)
create mode 100644 .gitignore
create mode 100644 .idea/.gitignore
create mode 100644 .idea/dbnavigator.xml
create mode 100644 .idea/encodings.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/vcs.xml
create mode 100644 .smarttomcat/JSP_Servlet_Template/conf/server.xml
create mode 100644 .smarttomcat/JSP_Servlet_Template/conf/web.xml
create mode 100644 .smarttomcat/Jsp_register/conf/server.xml
create mode 100644 .smarttomcat/Jsp_register/conf/web.xml
create mode 100644 pom.xml
create mode 100644 readme.md
create mode 100644 src/main/java/example/controller/RegisterServlet.java
create mode 100644 src/main/java/example/controller/UserListServlet.java
create mode 100644 src/main/java/example/dao/UserDao.java
create mode 100644 src/main/java/example/model/User.java
create mode 100644 src/main/java/example/utils/DBUtil.java
create mode 100644 src/main/java/example/utils/DBUtils.java
create mode 100644 src/main/webapp/WEB-INF/web.xml
create mode 100644 src/main/webapp/index.jsp
create mode 100644 src/main/webapp/register.jsp
create mode 100644 src/main/webapp/userList.jsp
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 0000000..98d00af
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,402 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..4b661a5
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.smarttomcat/JSP_Servlet_Template/conf/server.xml b/.smarttomcat/JSP_Servlet_Template/conf/server.xml
new file mode 100644
index 0000000..d9a36b4
--- /dev/null
+++ b/.smarttomcat/JSP_Servlet_Template/conf/server.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.smarttomcat/JSP_Servlet_Template/conf/web.xml b/.smarttomcat/JSP_Servlet_Template/conf/web.xml
new file mode 100644
index 0000000..5e81203
--- /dev/null
+++ b/.smarttomcat/JSP_Servlet_Template/conf/web.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+ index.html
+ index.htm
+ index.jsp
+
+
+
+
+ html
+ text/html
+
+
+ txt
+ text/plain
+
+
+ jpg
+ image/jpeg
+
+
+ png
+ image/png
+
+
+
+
+ jsp
+ org.apache.jasper.servlet.JspServlet
+
+ fork
+ false
+
+ 3
+
+
+
+ jsp
+ *.jsp
+
+
+
+
\ No newline at end of file
diff --git a/.smarttomcat/Jsp_register/conf/server.xml b/.smarttomcat/Jsp_register/conf/server.xml
new file mode 100644
index 0000000..d9a36b4
--- /dev/null
+++ b/.smarttomcat/Jsp_register/conf/server.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.smarttomcat/Jsp_register/conf/web.xml b/.smarttomcat/Jsp_register/conf/web.xml
new file mode 100644
index 0000000..3dfcd12
--- /dev/null
+++ b/.smarttomcat/Jsp_register/conf/web.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+ index.html
+ index.htm
+ index.jsp
+
+
+
+
+ html
+ text/html
+
+
+ txt
+ text/plain
+
+
+ jpg
+ image/jpeg
+
+
+ png
+ image/png
+
+
+
+
+ jsp
+ org.apache.jasper.servlet.JspServlet
+
+ fork
+ false
+
+ 3
+
+
+
+ jsp
+ *.jsp
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..47e76a9
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,92 @@
+
+ 4.0.0
+ org.example
+ JSP_Servlet_Template
+ war
+ 1.0-SNAPSHOT
+ JSP_Servlet_Template Maven Webapp
+ http://maven.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+ provided
+
+
+
+
+ javax.servlet.jsp
+ javax.servlet.jsp-api
+ 2.3.3
+ provided
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.33
+
+
+
+ commons-dbutils
+ commons-dbutils
+ 1.7
+
+
+
+ com.mchange
+ c3p0
+ 0.9.5.5
+
+
+
+
+
+
+ javax.servlet
+ jstl
+ 1.2
+
+
+
+
+ org.apache.tomcat
+ tomcat-servlet-api
+ 9.0.41
+ provided
+
+
+
+
+ org.apache.tomcat
+ tomcat-jasper
+ 9.0.41
+ provided
+
+
+
+ JSP_Servlet_Template
+
+
+
+
+ public
+ aliyun nexus
+ https://maven.aliyun.com/repository/public
+
+ true
+
+
+
+
+
+
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..a0b7c4f
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,7 @@
+# jsp+servlet项目模板
+
+
+
+
+
+
diff --git a/src/main/java/example/controller/RegisterServlet.java b/src/main/java/example/controller/RegisterServlet.java
new file mode 100644
index 0000000..9cebadd
--- /dev/null
+++ b/src/main/java/example/controller/RegisterServlet.java
@@ -0,0 +1,48 @@
+package example.controller;
+
+import example.model.User;
+import example.dao.UserDao;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+@WebServlet("/register")
+public class RegisterServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ // 从请求中获取表单参数
+ String username = request.getParameter("username");
+ String password = request.getParameter("password");
+
+ // 创建用户对象
+ User user = new User(0,username, password);
+
+ UserDao userDao = new UserDao();
+ int save = 0;
+ try {
+ save = userDao.addUser("1","1");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ response.setContentType("text/html; charset=UTF-8");
+ response.setCharacterEncoding("UTF-8");
+ response.getWriter().println("
");
+ response.getWriter().println("");
+ if (save > 0) {
+ response.getWriter().println("注册成功~");
+ } else {
+ response.getWriter().println("注册失败~");
+ }
+ }
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ response.sendRedirect("register.jsp");
+ }
+}
diff --git a/src/main/java/example/controller/UserListServlet.java b/src/main/java/example/controller/UserListServlet.java
new file mode 100644
index 0000000..a2cff05
--- /dev/null
+++ b/src/main/java/example/controller/UserListServlet.java
@@ -0,0 +1,119 @@
+package example.controller;
+
+import example.model.User;
+import example.utils.DBUtil;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@WebServlet("/userList")
+public class UserListServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+ private static final int PAGE_SIZE = 3; // 每页显示的记录数
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+ int currentPage = 1; // 当前页码,默认第一页
+ String pageParam = request.getParameter("page");
+ if (pageParam!= null &&!pageParam.isEmpty()) {
+ currentPage = Integer.parseInt(pageParam);
+ }
+
+ String queryParam = request.getParameter("query"); // 获取查询条件参数
+ if (queryParam == null) {
+ queryParam = ""; // 设置默认值为空字符串,可根据实际情况调整
+ }
+ List userList = new ArrayList<>();
+
+ String sql = getSqlWithQuery(queryParam); // 根据查询条件获取对应的SQL语句
+ int offset = (currentPage - 1) * PAGE_SIZE;
+ ResultSet resultSet = DBUtil.executeQuery(sql, offset, PAGE_SIZE);
+ try {
+ while (resultSet.next()) {
+ User user = new User();
+ user.setId(resultSet.getInt("id"));
+ user.setUsername(resultSet.getString("username"));
+ user.setPassword(resultSet.getString("password"));
+ userList.add(user);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } finally {
+ DBUtil.closeResources(null, null, resultSet);
+ }
+
+ int totalCount = getTotalCount(queryParam); // 根据查询条件获取总记录数
+ int totalPages = (totalCount + PAGE_SIZE - 1) / PAGE_SIZE; // 计算总页数
+
+ String pageLinks = generatePageLinks(currentPage, totalPages, queryParam); // 生成带查询条件的页码链接
+
+ request.setAttribute("userList", userList);
+ request.setAttribute("currentPage", currentPage);
+ request.setAttribute("totalPages", totalPages);
+ request.setAttribute("pageLinks", pageLinks);
+ request.setAttribute("query", queryParam); // 将查询条件也设置为属性传递给JSP页面,用于回显等
+ request.getRequestDispatcher("/userList.jsp").forward(request, response);
+ }
+
+ private String getSqlWithQuery(String queryParam) {
+ StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM user");
+ if (queryParam!= null &&!queryParam.isEmpty()) {
+ sqlBuilder.append(" WHERE username LIKE '%").append(queryParam).append("%'"); // 简单示例,按用户名模糊查询
+ }
+ sqlBuilder.append(" LIMIT ?,?");
+ return sqlBuilder.toString();
+ }
+
+ private int getTotalCount(String queryParam) {
+ StringBuilder sqlBuilder = new StringBuilder("SELECT COUNT(*) FROM user");
+ if (queryParam!= null &&!queryParam.isEmpty()) {
+ sqlBuilder.append(" WHERE username LIKE '%").append(queryParam).append("%'"); // 按用户名模糊查询统计数量
+ }
+ ResultSet resultSet = DBUtil.executeQuery(sqlBuilder.toString());
+ int totalCount = 0;
+ try {
+ if (resultSet.next()) {
+ totalCount = resultSet.getInt(1);
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ } finally {
+ DBUtil.closeResources(null, null, resultSet);
+ }
+ return totalCount;
+ }
+
+ private String generatePageLinks(int currentPage, int totalPages, String queryParam) {
+ StringBuilder pageLinksBuilder = new StringBuilder();
+ pageLinksBuilder.append("");
+ return pageLinksBuilder.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/example/dao/UserDao.java b/src/main/java/example/dao/UserDao.java
new file mode 100644
index 0000000..db84996
--- /dev/null
+++ b/src/main/java/example/dao/UserDao.java
@@ -0,0 +1,43 @@
+package example.dao;
+
+import example.model.User;
+import example.utils.DBUtils;
+import org.apache.commons.dbutils.QueryRunner;
+import org.apache.commons.dbutils.handlers.BeanHandler;
+import org.apache.commons.dbutils.handlers.BeanListHandler;
+
+import java.util.List;
+
+public class UserDao {
+ private final QueryRunner queryRunner = new QueryRunner(DBUtils.getDataSource());
+
+ public int addUser(String name, String email) throws Exception {
+ String sql = "INSERT INTO user (username, password) VALUES (?, ?)";
+ return queryRunner.update(sql, name, email);
+ }
+
+ public User getUserById(int id) throws Exception {
+ String sql = "SELECT * FROM user WHERE id = ?";
+ return queryRunner.query(sql, new BeanHandler<>(User.class), id);
+ }
+
+ public List getAllUser() throws Exception {
+ String sql = "SELECT * FROM user";
+ return queryRunner.query(sql, new BeanListHandler<>(User.class));
+ }
+
+ public int updateUser(int id, String name, String email) throws Exception {
+ String sql = "UPDATE user SET username = ?, password = ? WHERE id = ?";
+ return queryRunner.update(sql, name, email, id);
+ }
+
+ public int deleteUser(int id) throws Exception {
+ String sql = "DELETE FROM user WHERE id = ?";
+ return queryRunner.update(sql, id);
+ }
+
+ public static void main(String[] args) throws Exception {
+ UserDao userDao = new UserDao();
+ System.out.println(userDao.getUserById(1).getUsername());
+ }
+}
diff --git a/src/main/java/example/model/User.java b/src/main/java/example/model/User.java
new file mode 100644
index 0000000..58b8a09
--- /dev/null
+++ b/src/main/java/example/model/User.java
@@ -0,0 +1,42 @@
+package example.model;
+
+import com.sun.xml.internal.bind.v2.model.core.ID;
+
+public class User {
+ private int id;
+ private String username;
+ private String password;
+
+ // 构造器
+ public User() {}
+
+ public User(int id,String username, String password) {
+ this.id= id;
+ this.username = username;
+ this.password = password;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/src/main/java/example/utils/DBUtil.java b/src/main/java/example/utils/DBUtil.java
new file mode 100644
index 0000000..1fbeae9
--- /dev/null
+++ b/src/main/java/example/utils/DBUtil.java
@@ -0,0 +1,50 @@
+package example.utils;
+
+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/guest_room_db?useSSL=false&serverTimezone=UTC";
+ private static final String USERNAME = "root";
+ private static final String PASSWORD = "root";
+
+ public static Connection getConnection() throws SQLException {
+ return DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ }
+
+ public static void closeResources(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
+ try {
+ if (resultSet!= null) {
+ resultSet.close();
+ }
+ if (preparedStatement!= null) {
+ preparedStatement.close();
+ }
+ if (connection!= null) {
+ connection.close();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static ResultSet executeQuery(String sql, Object... params) {
+ Connection connection = null;
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ try {
+ connection = getConnection();
+ preparedStatement = connection.prepareStatement(sql);
+ for (int i = 0; i < params.length; i++) {
+ preparedStatement.setObject(i + 1, params[i]);
+ }
+ resultSet = preparedStatement.executeQuery();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return resultSet;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/example/utils/DBUtils.java b/src/main/java/example/utils/DBUtils.java
new file mode 100644
index 0000000..834acbe
--- /dev/null
+++ b/src/main/java/example/utils/DBUtils.java
@@ -0,0 +1,24 @@
+package example.utils;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+
+public class DBUtils {
+ private static ComboPooledDataSource dataSource;
+
+ static {
+ try {
+ dataSource = new ComboPooledDataSource();
+ dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
+ dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jsp_temp_db?useSSL=false&serverTimezone=UTC");
+ dataSource.setUser("root");
+ dataSource.setPassword("root");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static ComboPooledDataSource getDataSource() {
+ return dataSource;
+ }
+
+}
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..9c08442
--- /dev/null
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,6 @@
+
+ default
+
+ /js/*
+
+
\ No newline at end of file
diff --git a/src/main/webapp/index.jsp b/src/main/webapp/index.jsp
new file mode 100644
index 0000000..fe033e0
--- /dev/null
+++ b/src/main/webapp/index.jsp
@@ -0,0 +1,9 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+
+
+首页
+注册
+
+
diff --git a/src/main/webapp/register.jsp b/src/main/webapp/register.jsp
new file mode 100644
index 0000000..cf2fca0
--- /dev/null
+++ b/src/main/webapp/register.jsp
@@ -0,0 +1,18 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+
+
+
+
+ 用户注册
+
+
+
+
diff --git a/src/main/webapp/userList.jsp b/src/main/webapp/userList.jsp
new file mode 100644
index 0000000..9223a88
--- /dev/null
+++ b/src/main/webapp/userList.jsp
@@ -0,0 +1,38 @@
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ page import="java.util.List" %>
+<%@ page import="example.model.User" %>
+
+
+ 用户列表
+
+
+
+ 用户列表
+
+
+
+ ID |
+ 用户名 |
+ 密码 |
+
+
+
+ ${user.id} |
+ ${user.username} |
+ ${user.password} |
+
+
+
+
+ 当前第 ${currentPage} 页,共 ${totalPages} 页
+
+
+
\ No newline at end of file