{"id":21974110,"url":"https://github.com/javaobjects/tickets","last_synced_at":"2026-05-04T14:34:40.668Z","repository":{"id":105562637,"uuid":"205126298","full_name":"javaobjects/tickets","owner":"javaobjects","description":"Java EE(Filter + HttpSession + servlet + JDBC连接池 + 单例模式) + Jsp 购票网","archived":false,"fork":false,"pushed_at":"2024-04-22T06:55:07.000Z","size":8372,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-28T03:17:16.922Z","etag":null,"topics":["ajax","cookie","httpsession","jdbc","jsp","jxl","md5","servlet"],"latest_commit_sha":null,"homepage":"https://github.com/javaobjects/tickets","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mulanpsl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/javaobjects.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-29T09:17:42.000Z","updated_at":"2024-04-22T06:55:10.000Z","dependencies_parsed_at":"2024-11-29T15:41:13.333Z","dependency_job_id":"8bd859a7-aabb-4a4c-a1ae-29e9adb8ac32","html_url":"https://github.com/javaobjects/tickets","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaobjects%2Ftickets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaobjects%2Ftickets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaobjects%2Ftickets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javaobjects%2Ftickets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/javaobjects","download_url":"https://codeload.github.com/javaobjects/tickets/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245033722,"owners_count":20550319,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ajax","cookie","httpsession","jdbc","jsp","jxl","md5","servlet"],"created_at":"2024-11-29T15:38:04.015Z","updated_at":"2026-05-04T14:34:35.650Z","avatar_url":"https://github.com/javaobjects.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\r\n    \u003ca href='https://docs.oracle.com/en/java/javase/8'\u003e\u003cimg alt=\"Java 8\" src=\"./Img/Java8.png\"\u003e\u003c/a\u003e\r\n    \u003ca href='https://docs.spring.io/spring-boot/docs/2.6.2-SNAPSHOT/reference/html'\u003e\u003cimg alt=\"Spring Boot 2\" src=\"https://img.shields.io/badge/Spring%20Boot%202-%23000000.svg?logo=springboot\"\u003e\u003c/a\u003e\r\n    \u003ca href='https://staging-cn.vuejs.org'\u003e\u003cimg alt=\"Vue 3\" src=\"https://img.shields.io/badge/Vue%202%20-%232b3847.svg?logo=vue.js\"\u003e\u003c/a\u003e\u003cbr/\u003e\r\n    \u003ca href='#'\u003e\u003cimg alt=\"Github stars\" src=\"https://img.shields.io/github/stars/201206030/novel?logo=github\"\u003e\u003c/a\u003e\r\n    \u003ca href='#'\u003e\u003cimg alt=\"Github forks\" src=\"https://img.shields.io/github/forks/201206030/novel?logo=github\"\u003e\u003c/a\u003e\r\n    \u003ca href='#'\u003e\u003cimg alt=\"Gitee stars\" src=\"https://gitee.com/novel_dev_team/novel/badge/star.svg?theme=gitee\"\u003e\u003c/a\u003e\r\n    \u003ca href='#'\u003e\u003cimg alt=\"Gitee forks\" src=\"https://gitee.com/novel_dev_team/novel/badge/fork.svg?theme=gitee\"\u003e\u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n# 购票网\r\n\r\n#### 项目说明\r\n\r\n+ 此项目为JavaWeb项目，后端纯Java未使用框架，前端为Jsp，实现了前后端数据通信，前后端基本的增删改查功能。\r\n\r\n#### 开发环境\r\n\r\n+ Windows\r\n\r\n#### 配置环境\r\n\r\n| 程序           | 版本        | 说明                       |\r\n|--------------|-----------|--------------------------|\r\n| Jdk          | 1.8.0 161 | Java 开发工具包               |\r\n| Mysql        | 5.5.27    | 关系型数据库                   |\r\n| 或者 Oracle    | 11.2.0.1.0    | 关系型数据库                   |\r\n| Apache-Tomcat | 9.0.71     | Java 服务器           |\r\n\r\n#### 开发工具\r\n\r\n| 工具                       | 版本            | 说明                      |\r\n|--------------------------|---------------|-------------------------|\r\n| Eclipse IDE              | 4.11.0(2022.12)| 后端开发IDE                |\r\n| Vscode IDE              | 1.34.0| 前端开发IDE                |\r\n| Git                      | 2.24.1        | 代码托管平台                  |\r\n| Google   Chrome          | 75.0.3770.100 | 浏览器、前端调试工具              |\r\n| Navicat                  | 12       | 数据库连接工具                 |\r\n| PL/SQL                  | 11.2.0.1.0       | 数据库连接工具                 |\r\n| Postman                  | 7.1.0         | 接口测试工具                  |\r\n| VMware   Workstation Pro | 14.1.3        | 虚拟机(未用到或许你会用到)          |\r\n| PowerDesigner            | 15            | 数据库设计工具(未用到或许你会用到)      |\r\n| SQLyog                   | 12.0.3        | 数据库连接工具 (未用到或许你会用到)     |\r\n| Visio                    | 2013          | 时序图、流程图等绘制工具(未用到或许你会用到) |\r\n| ProcessOn                | ——            | 架构图等绘制工具(未用到或许你会用到)     |\r\n| XMind   ZEN              | 9.2.0         | 思维导图绘制工具(未用到或许你会用到)     |\r\n| RedisDesktop             | 0.9.3.817     | redis客户端连接工具(未用到或许你会用到) |\r\n\r\n####  编码规范\r\n\r\n- 规范方式：严格遵守阿里编码规约。\r\n- 命名统一：简介最大程度上达到了见名知意。\r\n- 分包明确：层级分明可快速定位到代码位置。\r\n- 注释完整：描述性高大量减少了开发人员的代码阅读工作量。\r\n- 工具规范：使用统一jar包避免出现内容冲突。\r\n- 代码整洁：可读性、维护性高。\r\n\r\n#### 包结构\r\n\r\n```\r\n +- tickets\r\n     +- Img --md文件所需的图片\r\n     +- sql --sql语句包\r\n     +- txt --部分知识点总结\r\n        +- src\r\n        \t+- main\r\n        \t|\t+- java\r\n        \t|\t|\t+- net\r\n        \t|\t|\t\t+- tencent\r\n        \t|\t|\t\t|\t+- tickets\r\n        \t|\t|\t\t|\t\t+- dao -- 数据访问层，与底层 MySQL 进行数据交互\r\n        \t|\t|\t\t|\t\t+- entity --实体\r\n        \t|\t|\t\t|\t\t+- filter --过滤器，控制前端页面访问\r\n        \t|\t|\t\t|\t\t+- service --dao与servlet解耦合\r\n        \t|\t|\t\t|\t\t+- servlet -- 主要是处理各种 Http 请求，各类基本参数校验，或者不复用的业务简单处理，返回 JSON 数据等\r\n        \t|\t|\t\t|\t\t|\t+- admin\r\n        \t|\t|\t\t|\t\t|\t+- comm\r\n        \t|\t|\t\t|\t\t|\t+- login\r\n        \t|\t|\t\t|\t\t|\t+- user\r\n        \t|\t|\t\t|\t\t+- util -- 业务相关工具\r\n        \t|\t+- webapp\r\n        \t|\t|\t+- admin -- 管理员前端页面\r\n        \t|\t|\t+- css -- 样式\r\n        \t|\t|\t+- images -- 图片\r\n        \t|\t|\t+- js -- 前端页面行为逻辑控制\r\n        \t|\t|\t+- META-INF\r\n        \t|\t|\t\t+- context.xml -- 数据库的配置\r\n        \t|\t|\t+- photos -- 用户上传头像客户端存储位置\r\n        \t|\t|\t+- user -- 用户前端界面\r\n        \t|\t|\t+- WEB-INF\r\n        \t\t\t\t+- lib -- 存放此项目所用的各种jar包\r\n        \t\t\t\t+- web.xml -- 配置默认显示的前端页面和过滤器的配置\r\n```\r\n\r\n#### 项目所导入的Jar包\r\n\r\n1. jstl-1.2.jar (JSP标准标签库)\r\n2. [jxl.jar](https://bbs.csdn.net/topics/90494976)(Java操作Excel或创建Excel) \r\n3. ojdbc6.jar Oracle数据驱动\r\n3. mysql-connector-java-5.1.39-bin.jar mysql数据驱动\r\n3. Java生成Json传输给前端的接口驱动\r\n\r\n```\r\ncommons-beanutils-1.7.0.jar\r\ncommons-collections-3.1.jar\r\ncommons-lang-2.5.jar\r\ncommons-logging-1.1.1.jar\r\nezmorph-1.0.3.jar\r\njson-lib-2.1-jdk15.jar\r\n```\r\n\r\n6. 上传照片功能需要的jar包\r\n\r\n```\r\ncommons-fileupload-1.3.1.jar\r\ncommons-io-2.4.jar\r\n```\r\n\r\n#### 搭建运行本项目步骤\r\n\r\n1. 确保已配置好jdk1.8的环境且与Eclipse开发工具相匹配\r\n2. 确保已安装好Tomcat配置环境且和Eclipse开发工具配置完成\r\n3. 导入了以应的jar包\r\n\r\n```\r\n右键项目 --\u003eBuild Path --\u003e Configure Build Path --\u003e Java Build Path\r\n--\u003e Libraries(Class path) --\u003e Add JARs.. --\u003e 选择要导入的包可多选 --\u003e Apply and close\r\n```\r\n\r\n![](Img/12.png)\r\n\r\n4. 将tickets_all.sql导入自己的navicat执行并生成对应的mysql数据库数据 前提是要配置好自己的mysql数据库跟navicat可视化工具\r\n5. 配置自己mysql数据库在META-INF下的context.xml\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003cContext\u003e\r\n\t\u003cResource name=\"jdbc/mysql\" \r\n\tauth=\"Container\" \r\n\ttype=\"javax.sql.DataSource\"\r\n\tusername=\"root\"\r\n\tpassword=\"123456\"\r\n\turl=\"jdbc:mysql://localhost:3306/tickets\"\r\n\tdriverClassName=\"com.mysql.jdbc.Driver\"\r\n\tmaxIdle=\"2\"\r\n\tmaxWait=\"5000\"\r\n\tmaxActive=\"4\" /\u003e\r\n\u003c/Context\u003e\r\n```\r\n\r\n6. 配置默认显示页面以及拦截器 WEB-INF下的web.xml 当然拦截器需要自己完成对应的功能，这里只是配置\r\n\r\n```xml\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003cweb-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd\" id=\"WebApp_ID\" version=\"4.0\"\u003e\r\n  \u003cdisplay-name\u003etickets\u003c/display-name\u003e\r\n\r\n\u003c!--\t拦截器--\u003e\r\n\t\u003cfilter\u003e\r\n\t\t\u003cfilter-name\u003ef1\u003c/filter-name\u003e\r\n\t\t\u003cfilter-class\u003enet.tencent.tickets.filter.AccessFilter\u003c/filter-class\u003e\r\n\t\u003c/filter\u003e\r\n\t\u003cfilter-mapping\u003e\r\n\t\t\u003cfilter-name\u003ef1\u003c/filter-name\u003e\r\n\t\t\u003curl-pattern\u003e/*\u003c/url-pattern\u003e\r\n\t\u003c/filter-mapping\u003e\r\n\u003c!--  默认显示页面--\u003e\r\n  \u003cwelcome-file-list\u003e\r\n    \u003cwelcome-file\u003eindex.html\u003c/welcome-file\u003e\r\n    \u003cwelcome-file\u003elogin.jsp\u003c/welcome-file\u003e\r\n    \u003cwelcome-file\u003eindex.htm\u003c/welcome-file\u003e\r\n    \u003cwelcome-file\u003edefault.html\u003c/welcome-file\u003e\r\n    \u003cwelcome-file\u003edefault.jsp\u003c/welcome-file\u003e\r\n    \u003cwelcome-file\u003edefault.htm\u003c/welcome-file\u003e\r\n  \u003c/welcome-file-list\u003e\r\n\u003c/web-app\u003e\r\n```\r\n\r\n7. 在Eclipse里导入此项目--\u003e右键此项目--\u003eRun As--\u003eRun On Server--\u003e在弹出的对话框选择自己的Tomcat--\u003eNext--\u003eFinish--\u003e启动成功后你的默认浏览器会自动弹出一个名为 http://localhost:8080/tickets/ 的页面表明启动成功\r\n\r\n![](Img/JB-1.png)\r\n\r\n![](Img/JB-2.png)\r\n\r\n![](Img/JB-3.png)\r\n\r\n![](Img/JB-4.png)\r\n\r\n8. txt文件夹有部分知识点总结\r\n\r\n####  项目所用技术点 \r\n\r\n1. 访问控制过滤器Filter的使用\r\n2. HttpSession的使用\r\n3. servlet传递数据至Jsp\r\n4. JDBC连接池的使用\r\n5. Jsp EL表达式 \r\n6. Jsp核心标签库的运用\r\n7. ajax输出xml或Json使用\r\n8. Md5加密技术\r\n9. 图形验证码技术\r\n10. Cookie的使用\r\n11. 图片上传\r\n12. 服务端表格分页\r\n13. 导出一个xls Excel表格\r\n14. 单例模式的使用\r\n\r\n```\r\n//\t 单例模式实现步骤：\r\n//\t 1.构造器私有\r\n//\t 2.提供私有的静态的当前类类型的变量\r\n//\t 3.提供一个公共的静态方法，返回刚才定义的变量，如果这个变量为null，那么给他赋值\r\n```\r\n\r\n+ 核心代码示例代码 Service\r\n\r\n```Java\r\npackage net.tencent.tickets.service;\r\n\r\nimport java.util.List;\r\n\r\nimport net.tencent.tickets.dao.CityDao;\r\nimport net.tencent.tickets.entity.City;\r\n\r\npublic class CityService {\r\n\t\r\n\t//属性依赖cityDao\r\n\tprivate CityDao cityDao = CityDao.getInstance();\r\n\t\r\n\t/**\r\n\t * \r\n\t * \u003cp\u003eTitle: getCityByProvinceNum\u003c/p\u003e  \r\n\t * \u003cp\u003e\r\n\t *\tDescription: \r\n\t *\t获取指定省份的城市信息的业务方法\r\n\t * \u003c/p\u003e \r\n\t * @param provinceNum\r\n\t * @return\r\n\t */\r\n\tpublic List\u003cCity\u003e getCityByProvinceNum(String provinceNum) {\r\n\t\treturn cityDao.queryCityByProvinceNum(provinceNum);\r\n\t}\r\n\t/**\r\n\t * \u003cp\u003eTitle: queryCityByCityNum\u003c/p\u003e\r\n\t * \u003cp\u003e\r\n\t *    Description:\r\n\t * \u003c/p\u003e\r\n\t * \u003cp\u003eCopyright: Copyright (c) 2017\u003c/p\u003e\r\n\t * \u003cp\u003eCompany: www.baidudu.com\u003c/p\u003e\r\n\t * @param cityNum\r\n\t * @return\r\n\t * @author xianxian\r\n\t * @date 2023年3月2日下午6:08:03\r\n\t * @version 1.0\r\n\t */\r\n\tpublic City queryCityByCityNum(String cityNum) {\r\n\t\treturn cityDao.queryCityByCityNum(cityNum);\r\n\t}\r\n\t\r\n\tprivate CityService(){}\r\n\t\r\n\tprivate static CityService cityService;\r\n\t\r\n\tpublic static CityService getInstance() {\r\n\t\tif (cityService == null) {\r\n\t\t\tcityService = new CityService();\r\n\t\t}\r\n\t\treturn cityService;\r\n\t}\r\n\r\n}\r\n```\r\n\r\n+ dao\r\n\r\n```Java\r\npackage net.tencent.tickets.dao;\r\n\r\nimport java.sql.Connection;\r\nimport java.sql.PreparedStatement;\r\nimport java.sql.ResultSet;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport net.tencent.tickets.entity.City;\r\nimport net.tencent.tickets.entity.Province;\r\nimport net.tencent.tickets.service.ProvinceService;\r\nimport net.tencent.tickets.servlet.other.ProvinceServlet;\r\nimport net.tencent.tickets.util.DBUtils_pool;\r\n\r\npublic class CityDao {\r\n\t\r\n\t/** 根据省份编号查询所有城市的sql语句 **/\r\n\tprivate static final String QUERY_CITY_BY_PROVINCENUM = \r\n\t\t\t\"SELECT CITY_ID,CITY_NUM,CITY_NAME,CITY_FATHER from tickets_city where CITY_FATHER=?\";\r\n\t\r\n\t/** 根据城市编号查询城市所有  **/\r\n\t\r\n\tprivate static final String QUERY_CITY_BY_CITYNUM = \r\n\t\t\t\"SELECT CITY_ID,CITY_NUM,CITY_NAME,CITY_FATHER from tickets_city where CITY_NUM=?\";\r\n\t\r\n\t\r\n\t/**\r\n\t * \u003cp\u003eTitle: queryCityByCityNum\u003c/p\u003e\r\n\t * \u003cp\u003e\r\n\t *    Description:\r\n\t * \u003c/p\u003e\r\n\t * \u003cp\u003eCopyright: Copyright (c) 2017\u003c/p\u003e\r\n\t * \u003cp\u003eCompany: www.baidudu.com\u003c/p\u003e\r\n\t * @param cityNum\r\n\t * @return\r\n\t * @author xianxian\r\n\t * @date 2023年3月2日下午6:08:47\r\n\t * @version 1.0\r\n\t */\r\n\tpublic City queryCityByCityNum(String cityNum) {\r\n\t\tCity city = new City();\r\n\t\tConnection conn = null;\r\n\t\tPreparedStatement stmt = null;\r\n\t\tResultSet rs = null;\r\n\t\ttry {\r\n\t\t\tconn = DBUtils_pool.getConnection();\r\n\t\t\tstmt = conn.prepareStatement(QUERY_CITY_BY_CITYNUM);\r\n\t\t\tstmt.setString(1, cityNum);\r\n\t\t\trs = stmt.executeQuery();\r\n\t\t\twhile (rs.next()) {\r\n\t\t\t\tcity.setCityNum(rs.getString(\"CITY_NUM\"));\r\n\t\t\t\tcity.setId(rs.getInt(\"CITY_ID\"));\r\n\t\t\t\tcity.setCityName(rs.getString(\"CITY_NAME\"));\r\n\t\t\t\t\r\n\t\t\t\tProvinceService provinceService = ProvinceService.getInstance();\r\n\t\t\t\tProvince province = provinceService.queryProvinceByProvinceNum(rs.getString(\"CITY_FATHER\"));\r\n\t\t\t\t\r\n\t\t\t\tcity.setProvince(province);\r\n\t\t\t}\r\n\t\t} catch (Exception e) {\r\n\t\t\te.printStackTrace();\r\n\t\t} finally {\r\n\t\t\tDBUtils_pool.release(conn, stmt, rs);\r\n\t\t}\r\n\t\treturn city;\r\n\t}\r\n\t\r\n\r\n\t\r\n\t/**\r\n\t * (non-Javadoc)\r\n\t * \u003cp\u003eTitle: queryCityByProvinceNum\u003c/p\u003e\r\n\t * \u003cp\u003e\r\n\t *    Description:获取指定省份的所有城市信息\r\n\t * \u003c/p\u003e\r\n\t * \u003cp\u003eCopyright: Copyright (c) 2017\u003c/p\u003e\r\n\t * \u003cp\u003eCompany: www.baidudu.com\u003c/p\u003e\r\n\t * @param provinceNum\r\n\t * @return\r\n\t * @see net.tencent.tickets.dao.ifac.CityDaoIfac#queryCityByProvinceNum(java.lang.String)\r\n\t * @author xianxian\r\n\t * @date 2023年2月25日下午9:10:45\r\n\t * @version 1.0\r\n\t */\r\n\tpublic List\u003cCity\u003e queryCityByProvinceNum(String provinceNum) {\r\n\t\tList\u003cCity\u003e cities = new ArrayList\u003c\u003e();\r\n\t\tConnection conn = null;\r\n\t\tPreparedStatement stmt = null;\r\n\t\tResultSet rs = null;\r\n\t\ttry {\r\n\r\n\t\t\tconn = DBUtils_pool.getConnection();\r\n\t\t\tstmt = conn.prepareStatement(QUERY_CITY_BY_PROVINCENUM);\r\n\t\t\tstmt.setString(1, provinceNum);\r\n\t\t\trs = stmt.executeQuery();\r\n\t\t\twhile (rs.next()) {\r\n\t\t\t\tCity c = new City();\r\n\r\n\t\t\t\tc.setCityNum(rs.getString(\"CITY_NUM\"));\r\n\t\t\t\tc.setId(rs.getInt(\"CITY_ID\"));\r\n\t\t\t\tc.setCityName(rs.getString(\"CITY_NAME\"));\r\n\t\t\t\tc.setProvince(new Province(null,rs.getString(\"CITY_FATHER\"),null));\r\n\r\n\t\t\t\tcities.add(c);\r\n\r\n\t\t\t}\r\n\t\t} catch (Exception e) {\r\n\t\t\te.printStackTrace();\r\n\t\t} finally {\r\n\t\t\tDBUtils_pool.release(conn, stmt, rs);\r\n\t\t}\r\n\t\treturn cities;\r\n\t}\r\n\r\n//\t 单例模式实现步骤：\r\n//\t 1.构造器私有\r\n//\t 2.提供私有的静态的当前类类型的变量\r\n//\t 3.提供一个公共的静态方法，返回刚才定义的变量，如果这个变量为null，那么给他赋值\r\n\tprivate CityDao() {};\r\n\tprivate static CityDao cityDao;\r\n\tpublic static CityDao getInstance() {\r\n\t\tif(cityDao == null) {\r\n\t\t\tcityDao = new CityDao();\r\n\t\t}\r\n\t\treturn cityDao;\r\n\t}\r\n}\r\n```\r\n\r\n+ 调用\r\n\r\n```Java\r\nCityService cityService = CityService.getInstance();\r\nCity city = cityService.queryCityByCityNum(cityNum);\r\n```\r\n\r\n\r\n#### 本项目的思维导向图草图\r\n\r\n![](Img/12306.png)\r\n\r\n#### 总体架构\r\n\r\n![](Img/JavaEE应用的标准层次结构.png)\r\n\r\n![](Img/%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8md5%E5%8A%A0%E5%AF%86%E5%AF%86%E7%A0%81%E7%9A%84%E4%BB%A3%E7%A0%81%E4%BF%AE%E6%94%B9%E8%AF%B4%E6%98%8E.png)\r\n\r\n![](Img/%E7%94%A8%E6%88%B7%E6%9B%B4%E6%96%B0%E4%BF%A1%E6%81%AF%E5%8A%9F%E8%83%BD%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%B5%81%E7%A8%8B.png)\r\n\r\n![](Img/%E7%A1%AE%E4%BF%9Dhttp%E8%AF%B7%E6%B1%82%E7%8A%B6%E6%80%81%E8%BF%9E%E7%BB%AD%E7%9A%84%E4%BC%9A%E8%AF%9D%E6%8A%80%E6%9C%AFHttpSession.png)\r\n\r\n![](Img/%E8%BF%87%E6%BB%A4%E5%99%A8%E7%9A%84%E4%BD%BF%E7%94%A8%E5%8E%9F%E7%90%86.png)\r\n\r\n![](Img/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0.png)\r\n\r\n\r\n#### 数据库设计\r\n\r\n##### tickets_user\r\n\r\n|列名|数据类型|可否为空|说明|\r\n| -- | -- | -- | -- |\r\n| USER_ID | number(11)    | not null  | id(Parimary主键)  |\r\n| USER_NAME | varchar2(30)   | not null | 用户名(Unique唯一)   |\r\n| USER_PASSWORD | varchar2(50)   | not null | 密码   |\r\n| USER_RULE | varchar2(2)  | not null | 权限(1 管理员 2 普通用户) |\r\n| USER_REAL_NAME | varchar2(50)   | not null | 真实姓名   |\r\n| USER_SEX | char(1)    | not null | 性别(1 男 2 女)   |\r\n| USER_CITY_ID | number(11)    | not null | 城市信息id值(Foreign外键tickets_city)FK_TICKETS_CITY_ID |\r\n| USER_CERTTYPE_ID | number(11)    | not null | 证件类型(1二代身份证2港澳通行证3台湾通行证4护照)(Foreign外键tickets_certtype)FK_TICKETS_CERTTYPE_ID |\r\n| USER_CERT | varchar2(50)    | not null | 证件号码   |\r\n| USER_BIRTHDAY | date   | not null | 生日   |\r\n| USER_USERTYPE_ID | number(11)   | not null | 旅客类型(1成人2儿童3学生4残疾军人、伤残人民警察)((Foreign外键tickets_usertype))FK_TICKETS_USERTYPE_ID |\r\n| USER_CONTENT | varchar2(3000)    | null   | 备注信息   |\r\n| USER_STATUS | char(1)   | not null | 用户状态(0 无效 1 有效)   |\r\n| USER_LOGIN_IP | varchar2(50)   | not null   | 登陆IP   |\r\n| USER_IMAGE_PATH | varchar2(200)    |  not null | 用户头像路径   |\r\n\r\n##### tickets_usertype\r\n\r\n|列名|数据类型|可否为空|说明|\r\n| -- | -- | -- | -- |\r\n| USERTYPE_ID | number(11)    | not null  | id (主键)  |\r\n| USERTYPE_CONTENT | varchar2(40)   | not null | 旅客类型(1成人2儿童3学生4残疾军人、伤残人民警察)    |\r\n\r\n##### tickets_province\r\n\r\n|列名|数据类型|可否为空|说明|\r\n| -- | -- | -- | -- |\r\n| PROVINCE_ID | number(11) | not null  | id (主键) |\r\n| PROVINCE_NUM | varchar2(50) | not null | 省份编号 |\r\n| PROVINCE_NAME | varchar2(40) | not null  | 省份名称  |\r\n\r\n##### tickets_city\r\n\r\n|列名|数据类型|可否为空|说明|\r\n| -- | -- | -- | -- |\r\n| CITY_ID | number(11) | not null  | id (主键) |\r\n| CITY_NUM | varchar2(50) | not null | 城市编号 |\r\n| CITY_NAME | varchar2(50) | not null  | 城市名称  |\r\n| CITY_FATHER | varchar2(6) | not null  | 省份标识(Foreign外键tickets_province)FK_TICKETS_PROVINCE_NUM |\r\n\r\n##### tickets_certtype\r\n\r\n|列名|数据类型|可否为空|说明|\r\n| -- | -- | -- | -- |\r\n| CERTTYPE_ID | number(11)    | not null  | id (主键)  |\r\n| CERTTYPE_CONTENT | varchar2(20)   | not null | 证件类型(1二代身份证2港澳通行证3台湾通行证4护照)|\r\n\r\n\r\n#### 本项目部分业务功能及其实现简介\r\n\r\n1. 验证码功能\r\n\r\n![](Img/GIF_1.gif)\r\n\r\n\r\n+ Java 利用26个英文字母以及十个数字随机组合成四位验证码\r\n+ 且字体颜色随机\r\n+ 干扰线随机\r\n+ 产生的验证码存入Session，并以图片的形式传给前端显示 \r\n+ 登录验证之时服务端取session里的验证码的值进行验证\r\n\r\n2. 自动登录功能\r\n\r\n![](Img/1.png)\r\n\r\n+ 前端将是否自动登录的标识传给Java后台\r\n\r\n+ Java根据标识将用户名与MD5加密后的密码存入前端的cookie中\r\n\r\n+ 前端每次登录之时判断浏览器中是否有存入cookie若有则取到用户名与密码直接发到到后台\r\n\r\n+ Java后台根据前端传入的用户名与密码实现自动登录的功能(有cookie且用户名与密码验证成功则跳过验证码实现自动登录)\r\n\r\n\r\n3. 管理员用户管理查询展示列表功能\r\n\r\n![](Img/GIF_2.gif)\r\n\r\n\r\n+ 当前端点击查询按钮时Java后台根据前端传入的数据进行查询并返回给前端\r\n+ 查询结果存入session\r\n\r\n```java\r\nPageUtil pageUtil = new PageUtil(users, Integer.parseInt(pageCount), 1);\r\nrequest.setAttribute(\"userList\", pageUtil.getUsers_page());// 把查询结果users传给userlist.jsp页面\r\nrequest.setAttribute(\"pagesum\", pageUtil.getPagesum());// 总页数\r\nrequest.setAttribute(\"pageNumber\", pageUtil.getPageNumber());// 页码\r\nrequest.getRequestDispatcher(\"/admin/userlist.jsp\").forward(request, response);\r\n```\r\n\r\n+ 前端根据查询结果返回的数据通过jsp页面的如下代码进行展示数据\r\n\r\n```jsp\r\n\u003cc:forEach items=\"${userList}\" var=\"u\" varStatus=\"status\"\u003e\r\n\r\n    \u003ctr align=\"center\"\u003e\r\n        \u003ctd bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e\u003cinput type=\"checkbox\" name=\"checkbox\"\r\n                                                            value=\"${u.id}\"\u003e\u003c/td\u003e\r\n        \u003ctd width=\"98\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e${u.userName}\u003c/td\u003e\r\n        \u003ctd width=\"80\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e${u.userSex==49?\"男\":\"女\"}\u003c/td\u003e\r\n        \u003ctd width=\"132\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e${u.certType.content}\u003c/td\u003e\r\n        \u003ctd width=\"247\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e${u.userCert}\u003c/td\u003e\r\n        \u003ctd width=\"82\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e${u.userType.content}\u003c/td\u003e\r\n        \u003ctd width=\"89\" bordercolor=\"#FFFFFF\" class=\"text_cray1\"\u003e\r\n            \u003cspan class=\"text_red\" style=\"cursor:pointer;\"\u003e编辑\u003c/span\u003e\r\n        \u003c/td\u003e\r\n    \u003c/tr\u003e\r\n\r\n\u003c/c:forEach\u003e\r\n```\r\n\r\n4. 查询结果全选功能\r\n\r\n![](Img/GIF_3.gif)\r\n\r\n\r\n+ 前端功能实现\r\n\r\n```javascript\r\nlet objMethod = {\r\n    selectAllNullorReserve: function (order) {\r\n        let checkboxArray = $('input[type=\"checkbox\"]');\r\n        switch (order) {\r\n            case \"全选\":\r\n                for (let i = 0; i \u003c checkboxArray.length; i++) {\r\n                    if (!checkboxArray.eq(i).attr(\"checked\")) {\r\n                        checkboxArray.eq(i).attr(\"checked\", true);\r\n                    }\r\n                }\r\n                break;\r\n            case \"全不选\":\r\n                for (let i = 0; i \u003c checkboxArray.length; i++) {\r\n                    if (checkboxArray.eq(i).attr(\"checked\")) {\r\n                        checkboxArray.eq(i).attr(\"checked\", false);\r\n                    }\r\n                }\r\n                break;\r\n            case \"反选\":\r\n                for (let i = 0; i \u003c checkboxArray.length; i++) {\r\n                    if (checkboxArray.eq(i).attr(\"checked\")) {\r\n                        checkboxArray.eq(i).attr(\"checked\", false);\r\n                    } else {\r\n                        checkboxArray.eq(i).attr(\"checked\", true);\r\n                    }\r\n                }\r\n                break;\r\n            default:\r\n                break;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n5. 分页展示功能\r\n\r\n![](Img/GIF_4.gif)\r\n\r\n\r\n+ Java后端分页 由于点击查询时所得到的结果都存入了session中，只需要将页码数值传入后端根据下标来截取对应的数值给前端就行了\r\n+ 前端展示即可\r\n\r\n```jsp\r\n\u003ctd width=\"154\" align=\"right\" class=\"text_cray1\" style=\"width:20%\"\u003e\u003clabel class=\"text_cray\"\u003e\r\n    每页显示\r\n    \u003cselect name=\"pageCount\" id=\"select_pageCount\"\u003e\r\n        \u003coption value=\"10\" ${pageCount.equals(\"10\")?\"selected\":\"\"}\u003e10\u003c/option\u003e\r\n        \u003coption value=\"20\" ${pageCount.equals(\"20\")?\"selected\":\"\"}\u003e20\u003c/option\u003e\r\n        \u003coption value=\"30\" ${pageCount.equals(\"30\")?\"selected\":\"\"}\u003e30\u003c/option\u003e\r\n    \u003c/select\u003e\r\n    条信息\u003c/label\u003e\r\n\u003c/td\u003e\r\n```\r\n\r\n```javascript\r\n// 分页改变时\r\n$(\"#select_pageCount\").change(function () {\r\n    $(\"#form_queryUser\").submit();\r\n})\r\n```\r\n\r\n```jsp\r\n\u003cform name=\"form1\" method=\"post\" id=\"form_queryUser\" action=\"\u003c%=request.getContextPath()%\u003e/AdminManageUserServlet?operator=queryUser\"\u003e\r\n```\r\n\r\n\r\n\r\n6. 点击页码跳转到对应的页的功能\r\n\r\n![](Img/GIF_5.gif)\r\n\r\n\r\n+ Java后端分页 由于点击查询时所得到的结果都存入了session中，只需要将页码数值传入后端根据下标来截取对应的数值给前端就行了\r\n+ 前端展示即可\r\n\r\n```jsp\r\n\u003ctd width=\"284\" align=\"center\" class=\"text_cray\"\u003e\u003e\u003e\r\n\r\n    \u003c% Integer pagesum = (Integer) request.getAttribute(\"pagesum\");\r\n    Integer pageNumber = (Integer) request.getAttribute(\"pageNumber\");\r\n    if (pagesum != null \u0026\u0026 pagesum != 0) {\r\n        for (int i = 1; i \u003c= pagesum; i++) {\r\n            if (i == pageNumber) {\r\n                %\u003e\r\n    \u003ca href=\"#\" style=\"text-decoration: underline\"\u003e\u003c%=i%\u003e\u0026nbsp;\u0026nbsp;\u003c/a\u003e\r\n    \u003c%} else { %\u003e\r\n    \u003ca href=\"#\" onclick=\"queryUserByPage(\u003c%=i%\u003e)\" style=\"text-decoration:none;\"\u003e\u003c%=i%\u003e\u0026nbsp;\u0026nbsp;\u003c/a\u003e\r\n    \u003c%}}}%\u003e\r\n    \u003cscript\u003e\r\n        function queryUserByPage(i) {\r\n            // alert(1);\r\n            var form = document.getElementById(\"form_queryUser\");\r\n            form.action = \"\u003c%=request.getContextPath()%\u003e/AdminManageUserServlet?operator=queryUserByPage\u0026pageNumber=\" + i;\r\n            form.submit();\r\n            form.action = \"\u003c%=request.getContextPath()%\u003e/AdminManageUserServlet?operator=queryUser\";//请还原，否则点击查询按钮会分页查询\r\n        }\r\n    \u003c/script\u003e\r\n    \u0026lt;\u0026lt;\r\n\u003c/td\u003e\r\n```\r\n\r\n7. Excel导出功能\r\n\r\n![](Img/2.png)\r\n\r\n\r\n\r\n![](Img/3.png)\r\n\r\n\r\n+ 导入对应的jar包到对应的lib文件夹下 jxl.jar\r\n\r\n```java\r\nprivate void exportExcel(HttpServletRequest request,\r\n                         HttpServletResponse response) throws ServletException, IOException{\r\n\r\n    HttpSession session = request.getSession();\r\n\r\n    @SuppressWarnings(\"unchecked\")\r\n    List\u003cUsers\u003e users = (List\u003cUsers\u003e)session.getAttribute(\"users\");\r\n\r\n    if(users == null || users.size() == 0)\r\n    {\r\n        response.setContentType(\"text/html;charset=utf-8\");\r\n        response.getWriter().println(\"\u003cscript\u003ealert('请先查询');\u003c/script\u003e\");\r\n    }else\r\n    {\r\n        response.setHeader(\"Content-disposition\", \"attachment; filename=\"\r\n                           + new String(\"用户\".getBytes(\"GB2312\"), \"8859_1\") + \r\n                           \".xls\");\r\n        response.setHeader(\"pragma\", \"no-cache\");\r\n        response.setContentType(\"application/msexcel\");\r\n        ServletOutputStream os = response.getOutputStream();\r\n        WritableWorkbook workbook = Workbook.createWorkbook(os);\r\n\r\n        WritableSheet ws = workbook.createSheet(\"用户列表\", 0);\r\n\r\n        try {\r\n            //首先写表头：id username\r\n            ws.addCell(new Label(0, 0, \"id\"));\r\n            ws.addCell(new Label(1, 0, \"用户名\"));\r\n            ws.addCell(new Label(2, 0, \"性别\"));\r\n            ws.addCell(new Label(3, 0, \"证件类型\"));\r\n            ws.addCell(new Label(4, 0, \"证件号码\"));\r\n            ws.addCell(new Label(5, 0, \"旅客类型\"));\r\n\r\n\r\n            for(int row = 1;row \u003c= users.size();row++)\r\n            {\r\n                Users user = users.get(row-1);\r\n                ws.addCell(new Label(0, row, user.getId()+\"\"));\r\n                ws.addCell(new Label(1, row, user.getUserName()));\r\n                ws.addCell(new Label(2, row, user.getUserSex() == 49 ? \"男\" : \"女\"));\r\n                ws.addCell(new Label(3, row, user.getCertType().getContent()));\r\n                ws.addCell(new Label(4, row, user.getUserCert()));\r\n                ws.addCell(new Label(5, row, user.getUserType().getContent()));\r\n            }\r\n\r\n            workbook.write();\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        }finally\r\n        {\r\n            try {\r\n                workbook.close();\r\n            } catch (WriteException e) {\r\n                e.printStackTrace();\r\n            }\r\n        }\r\n    }\t\r\n}\r\n```\r\n\r\n+ 前端调用即可\r\n\r\n8. 新增用户功能\r\n\r\n![](Img/4.png)\r\n\r\n+ 实现步骤\r\n+ 核心代码为一句sql语句\r\n\r\n```sql\r\n\tprivate static final String ADD_USER = \"INSERT INTO tickets_user(tickets_user.USER_ID,tickets_user.USER_NAME,tickets_user.USER_PASSWORD,tickets_user.USER_RULE,\\r\\n\"\r\n\t\t\t+ \"tickets_user.USER_REAL_NAME,tickets_user.USER_SEX,tickets_user.USER_CITY_ID,tickets_user.USER_CERTTYPE_ID,\\r\\n\"\r\n\t\t\t+ \"tickets_user.USER_CERT,tickets_user.USER_BIRTHDAY,tickets_user.USER_USERTYPE_ID,tickets_user.USER_CONTENT,tickets_user.USER_STATUS,tickets_user.USER_LOGIN_IP,tickets_user.USER_IMAGE_PATH)\\r\\n\"\r\n\t\t\t+ \"values (NULL,?,?,?,?,?,?,?,?,?,?,?,'1',?,'')\";\r\n```\r\n\r\n9. 展示当前在线人数功能\r\n\r\n![](Img/5.png)\r\n\r\n+ 实现步骤\r\n+ 在登录之时将统计核心代码如下\r\n\r\n```Java\r\n\t/**\r\n\t * 统计上线人数\r\n\t * @param request\r\n\t */\r\n\tprivate void online(HttpServletRequest request) {\r\n\t\tServletContext application = request.getServletContext();\r\n\t\tObject obj = application.getAttribute(\"onlineCount\");\r\n\t\t//第一次进来\r\n\t\tif(obj == null)\r\n\t\t{\r\n\t\t\tapplication.setAttribute(\"onlineCount\", 1);\r\n\t\t}\r\n\t\t//下一次进来\r\n\t\telse\r\n\t\t{\r\n\t\t\tapplication.setAttribute(\"onlineCount\", (Integer)obj + 1);\r\n\t\t}\r\n\t}\r\n```\r\n\r\n+ 前端展示\r\n\r\n```jsp\r\n    \u003ctd width=\"200\" valign=\"top\" bgcolor=\"#deedf8\" class=\"text_cray1\"\u003e\r\n    欢迎您，${sessionScope.user.userName}，\r\n      当前在线人数:${onlineCount }\r\n    \u003c/td\u003e\r\n```\r\n\r\n10. 欢迎XX用户功能\r\n\r\n![](Img/6.png)\r\n\r\n+ 实现步骤\r\n+ 登录之时存入了session，Java核心代码\r\n\r\n```java\r\n// 保存用户登陆信息-----------------------------session:在一次会话中保存数据\r\nsession.setAttribute(\"user\", user);\r\n```\r\n\r\n+ 前端展示\r\n\r\n```jsp\r\n\u003ctd width=\"200\" valign=\"top\" bgcolor=\"#deedf8\" class=\"text_cray1\"\u003e\r\n    欢迎您，${sessionScope.user.userName}，\r\n    当前在线人数:${onlineCount }\r\n\u003c/td\u003e\r\n```\r\n\r\n11. 退出登录功能\r\n\r\n![](Img/7.png)\r\n\r\n\r\n\r\n+ 后端清除cookie与session后跳转login页面即可\r\n\r\n12. 普通用户查看个人信息功能\r\n\r\n![](Img/8.png)\r\n\r\n\r\n\r\n+ 后台核心代码\r\n\r\n```sql\r\n\tprivate static final String QUERY_USER_BY_USERNAME_AND_PASSWORD = \"SELECT\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_NAME,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_PASSWORD,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_RULE,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_REAL_NAME,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_SEX,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_CITY_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_CERTTYPE_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_CERT,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_BIRTHDAY,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_USERTYPE_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_CONTENT,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_STATUS,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_LOGIN_IP,\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_IMAGE_PATH,\\r\\n\"\r\n\t\t\t+ \"\ttickets_city.CITY_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_city.CITY_NUM,\\r\\n\"\r\n\t\t\t+ \"\ttickets_city.CITY_NAME,\\r\\n\"\r\n\t\t\t+ \"\ttickets_city.CITY_FATHER,\\r\\n\"\r\n\t\t\t+ \"\ttickets_province.PROVINCE_ID,\\r\\n\"\r\n\t\t\t+ \"\ttickets_province.PROVINCE_NUM,\\r\\n\"\r\n\t\t\t+ \"\ttickets_province.PROVINCE_NAME,\\r\\n\"\r\n\t\t\t+ \"\ttickets_certtype.CERTTYPE_CONTENT,\\r\\n\"\r\n\t\t\t+ \"\ttickets_usertype.USERTYPE_CONTENT\\r\\n\"\r\n\t\t\t+ \"FROM\\r\\n\"\r\n\t\t\t+ \"\ttickets_user,\\r\\n\"\r\n\t\t\t+ \"\ttickets_city,\\r\\n\"\r\n\t\t\t+ \"\ttickets_province,\\r\\n\"\r\n\t\t\t+ \"\ttickets_certtype,\\r\\n\"\r\n\t\t\t+ \"\ttickets_usertype\\r\\n\"\r\n\t\t\t+ \"WHERE\\r\\n\"\r\n\t\t\t+ \"\ttickets_user.USER_CITY_ID = tickets_city.CITY_ID \\r\\n\"\r\n\t\t\t+ \"\tAND tickets_user.USER_USERTYPE_ID = tickets_usertype.USERTYPE_ID\\r\\n\"\r\n\t\t\t+ \"\tAND tickets_user.USER_CERTTYPE_ID = tickets_certtype.CERTTYPE_ID\\r\\n\"\r\n\t\t\t+ \"\tAND tickets_city.CITY_FATHER = tickets_province.PROVINCE_NUM\\r\\n\"\r\n\t\t\t+ \"\tAND tickets_user.USER_NAME = ? \"\r\n\t\t\t+ \"\tAND tickets_user.USER_PASSWORD = ? \";\r\n```\r\n\r\n+ 前端展示\r\n\r\n```jsp\r\n\u003ctable width=\"100%\" border=\"0\" cellspacing=\"0\"\u003e\r\n    \u003ctr\u003e\r\n        \u003ctd height=\"30\"\u003e\u0026nbsp;\u003c/td\u003e\r\n    \u003c/tr\u003e\r\n\u003c/table\u003e\r\n\u003ctable width=\"835\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\"\u003e\r\n    \u003ctr\u003e\r\n        \u003ctd height=\"20\" colspan=\"2\" align=\"center\" \u003e\u003c/td\u003e\r\n    \u003c/tr\u003e\r\n    \u003ctr\u003e\r\n        \u003ctd width=\"64\" align=\"center\" \u003e\u003c/td\u003e\r\n        \u003ctd width=\"771\" height=\"30\" align=\"left\" valign=\"top\" \u003e\r\n            \u003cspan class=\"text_blod_title\"\u003e查看个人信息\u003c/span\u003e\r\n        \u003c/td\u003e\r\n    \u003c/tr\u003e\r\n    \u003ctr\u003e\r\n        \u003ctd height=\"15\" colspan=\"2\" \u003e\r\n            \u003cimg src=\"\u003c%=request.getContextPath()%\u003e/images/line1.jpg\" width=\"835\" height=\"6\"\u003e\r\n        \u003c/td\u003e\r\n    \u003c/tr\u003e\r\n    \u003ctr\u003e\r\n        \u003ctd colspan=\"2\" valign=\"top\"  \u003e\u003ctable width=\"700\" border=\"0\" align=\"center\" cellpadding=\"0\" cellspacing=\"0\"\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd height=\"20\" colspan=\"4\"  \u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd height=\"15\" colspan=\"4\" align=\"left\" class=\"text_title\"\u003e个人详细信息\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd height=\"10\" colspan=\"4\" \u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e登录名：\u003c/td\u003e\r\n                \u003ctd width=\"350\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserName() %\u003e\u003c/td\u003e\r\n                \u003ctd width=\"230\" rowspan=\"5\" align=\"center\"\r\n                    background=\"\u003c%=request.getContextPath() %\u003e/images/bg_point_write.gif\" class=\"text_cray\"\u003e\r\n                    \u003cimg src=\"\u003c%=request.getContextPath()+\"/photos/\"+user.getUserImagePath() %\u003e\" width=\"139\" height=\"139\" id=\"userImage\"\u003e\r\n                \u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e真实姓名：\u003c/td\u003e\r\n                \u003ctd align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserRealName() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e性 别：\u003c/td\u003e\r\n                \u003ctd align=\"left\" class=\"text_cray\"\u003e\r\n                    ${userinfo.userSex == 49 ? \"男\" : \"女\"}\r\n                \u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e省份：\u003c/td\u003e\r\n                \u003ctd align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getCity().getProvince().getProvinceName() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e城市：\u003c/td\u003e\r\n                \u003ctd align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getCity().getCityName() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e证件类型：\u003c/td\u003e\r\n                \u003ctd colspan=\"2\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getCertType().getContent() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e证件号码：\u003c/td\u003e\r\n                \u003ctd colspan=\"2\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserCert() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" align=\"center\" class=\"text_red\"\u003e*\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e出生日期：\u003c/td\u003e\r\n                \u003ctd colspan=\"2\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserBirthday() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\" \u003e\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e旅客类型：\u003c/td\u003e\r\n                \u003ctd colspan=\"3\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserType().getContent() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003ctr\u003e\r\n                \u003ctd width=\"20\" height=\"40\"\u003e\u003c/td\u003e\r\n                \u003ctd width=\"100\" height=\"40\" align=\"left\" class=\"text_cray1\"\u003e备注：\u003c/td\u003e\r\n                \u003ctd height=\"40\" colspan=\"2\" align=\"left\" class=\"text_cray\"\u003e\u003c%=user.getUserContent() %\u003e\u003c/td\u003e\r\n            \u003c/tr\u003e\r\n            \u003c/table\u003e\r\n```\r\n\r\n\r\n\r\n13. 普通用户修改个人信息功能\r\n\r\n![](Img/9.png)\r\n\r\n+ 核心Java代码\r\n\r\n```Java\r\nString update_user_sql=\"UPDATE tickets_user \\r\\n\"\r\n    + \"SET tickets_user.USER_REAL_NAME =?,\\r\\n\"\r\n    + \"tickets_user.USER_SEX =?,\\r\\n\"\r\n    + \"tickets_user.USER_CITY_ID =?,\\r\\n\"\r\n    + \"tickets_user.USER_CERTTYPE_ID =?,\\r\\n\"\r\n    + \"tickets_user.USER_CERT =?,\\r\\n\"\r\n    + \"tickets_user.USER_BIRTHDAY =?,\\r\\n\"\r\n    + \"tickets_user.USER_USERTYPE_ID =?,\\r\\n\"\r\n    + \"tickets_user.USER_CONTENT =? \\r\\n\"\r\n    + \"WHERE\\r\\n\"\r\n    + \"\ttickets_user.USER_ID =?\";\r\n```\r\n\r\n14. 普通用户上传头像功能\r\n\r\n![](Img/10.png)\r\n\r\n+ 前端\r\n\r\n```jsp\r\n\u003ctd align=\"center\"\u003e\r\n    \u003cinput name=\"uploadFile\" type=\"file\" class=\"text_cray\" size=\"20\" id=\"txt_uploadFile\"/\u003e\r\n    \u003cinput type=\"button\" value=\"上传\" id=\"btn_uploadFile\"\r\n           style=\"position: relative;top: -21px;left: 70px;\" /\u003e\r\n\u003c/td\u003e\r\n```\r\n\r\n```javascript\r\ndocument.querySelector(\"#btn_uploadFile\").onclick = () =\u003e\r\n{\r\n    //txt_uploadFile\r\n    let txt_uploadFile = document.querySelector(\"#txt_uploadFile\").value;\r\n    if(txt_uploadFile){\r\n        //表单提交，上传照片，告诉我是成功还是失败，最好回显照片\r\n        //1.获取表单元素\r\n        let form = document.querySelector(\"#edit_form\");\r\n        //2.修改表单的属性：支持进行二进制数据的提交\r\n        form.encoding = \"multipart/form-data\";\r\n        //3.指定处理上传图片请求的servlet\r\n        form.action = \"UploadPhotoServlet\";\r\n        //4.表单提交\r\n        form.submit();\r\n        //以下代码将表单属性还原\r\n        //需要修改表单的enctype属性，js中的代码如下：\r\n        form.encoding = \"application/x-www-form-urlencoded\";\r\n        form.action = \"UpdateUserServlet\";\r\n    }else{\r\n        document.querySelector(\"#tip_text\").innerText = \"请先选择文件!\";\r\n    }\r\n}\r\ndocument.querySelector(\"#txt_uploadFile\").onclick = () =\u003e {\r\n    document.querySelector(\"#tip_text\").innerText = \"\";\r\n}\r\n```\r\n\r\n+ 后端代码\r\n\r\n```java\r\npackage net.tencent.tickets.servlet.user;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.io.PrintWriter;\r\n\r\nimport javax.servlet.ServletException;\r\nimport javax.servlet.annotation.MultipartConfig;\r\nimport javax.servlet.annotation.WebServlet;\r\nimport javax.servlet.http.HttpServlet;\r\nimport javax.servlet.http.HttpServletRequest;\r\nimport javax.servlet.http.HttpServletResponse;\r\nimport javax.servlet.http.HttpSession;\r\nimport javax.servlet.http.Part;\r\n\r\nimport net.tencent.tickets.entity.Users;\r\nimport net.tencent.tickets.service.UserService;\r\n\r\n/**\r\n * 负责处理上传照片的servlet\r\n */\r\n@WebServlet(\"/UploadPhotoServlet\")\r\n@MultipartConfig\r\npublic class UploadPhotoServlet extends HttpServlet {\r\n\tprivate static final long serialVersionUID = 1L;\r\n\r\n\t@Override\r\n\tprotected void service(HttpServletRequest request, HttpServletResponse response)\r\n\t\t\tthrows ServletException, IOException {\r\n\t\t/*\r\n\t\t * 1.后台使用servlet3.0技术上传照片\r\n\t\t * 2.上传照片需要指定服务器上照片保存的地址，photos文件夹保存照片\r\n\t\t * 3.所以要拿到照片的存储路径，方便回显数据\r\n\t\t */\r\n\t\t\r\n\t\trequest.setCharacterEncoding(\"utf-8\");\r\n\t\tresponse.setCharacterEncoding(\"utf-8\");\r\n\t\tresponse.setContentType(\"text/html;charset=utf-8\");\r\n\t\t\r\n\r\n\t\t// 获取上传的文件集合\r\n\t\t//Collection\u003cPart\u003e parts = request.getParts();\r\n\t\t// 上传单个文件\r\n\t\r\n\t\t\t// Servlet3.0将multipart/form-data的POST请求封装成Part，通过Part对上传的文件进行操作。\r\n\t\t\t// Part part = parts[0];//从上传的文件集合中获取Part对象\r\n\t\t\tPart part = request.getPart(\"uploadFile\");// 通过表单file控件(\u003cinput type=\"file\" name=\"file\"\u003e)的名字直接获取Part对象\r\n\t\t\t// Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来\r\n\t\t\t// 获取请求头，请求头的格式：form-data; name=\"file\"; filename=\"snmp4j--api.zip\"\r\n\t\t\tString header = part.getHeader(\"content-disposition\");\r\n\t\t\t\r\n\t\t\t// 获取文件名\r\n\t\t\tString fileName = getFileName(header);\r\n\t\t\t\r\n\t\t\t// 存储路径 存到了服务器的路径 客户端的文件夹是看不到的 布署完成后可直接使用\r\n\t\t\tString saveServletPath = request.getServletContext().getRealPath(\"/photos\") + File.separator + fileName;\r\n\t\t\t\r\n\t\t\t// 把文件写到指定路径\r\n\t\t\t//UUID.randomUUID()+\".jpg\"\r\n\t\t\tpart.write(saveServletPath);\r\n\r\n\t\t\t//把这个照片路径保存到数据库\r\n\t\t\tHttpSession session = request.getSession();\r\n\t\t\tUsers user_session = (Users)session.getAttribute(\"user\");\r\n\t\t\tUserService userService = UserService.getInstance();\r\n\t\t\tUsers user = userService.login(user_session.getUserName(), user_session.getUserPassword());\r\n\t\t\t\r\n\r\n\t\t\t//判断是否上传成功\r\n\t\t\tif(UserService.getInstance().saveImage(user.getId(),fileName)) {\r\n\t\t\t\t//回到更新用户信息页面，让用户看到自己的照片\r\n\t\t\t\tresponse.sendRedirect(\"ToUpdateUserServlet\");\r\n\t\t\t}else {\r\n\t\t\t\tPrintWriter pw = response.getWriter();\r\n\t\t\t\tpw.println(\"\u003cscript\u003ealert('上传照片失败，请稍后再试！');\u003c/script\u003e\");\r\n\t\t\t\tpw.flush();\r\n\t\t\t\tpw.close();\r\n\t\t\t}\r\n\t\t\t\r\n\t}\r\n\t/**\r\n\t * \r\n\t * \u003cp\u003eTitle: getFileName\u003c/p\u003e  \r\n\t * \u003cp\u003e\r\n\t *\tDescription: \r\n\t *\t根据请求头解析出文件名 请求头的格式：火狐和google浏览器下：form-data; name=\"file\";\r\n\t * filename=\"snmp4j--api.zip\" IE浏览器下：form-data; name=\"file\";\r\n\t * filename=\"E:\\snmp4j--api.zip\"\r\n\t * \u003c/p\u003e \r\n\t * @param header 请求头\r\n\t * @return 文件名\r\n\t */\r\n\tpublic String getFileName(String header) {\r\n\t\t/**\r\n\t\t * String[] tempArr1 =\r\n\t\t * header.split(\";\");代码执行完之后，在不同的浏览器下，tempArr1数组里面的内容稍有区别\r\n\t\t * 火狐或者google浏览器下：\r\n\t\t * tempArr1={form-data,name=\"file\",filename=\"snmp4j--api.zip\"}\r\n\t\t * IE浏览器下：tempArr1={form-data,name=\"file\",filename=\"E:\\snmp4j--api.zip\"}\r\n\t\t */\r\n\t\tString[] tempArr1 = header.split(\";\");\r\n\t\t/**\r\n\t\t * 火狐或者google浏览器下：tempArr2={filename,\"snmp4j--api.zip\"}\r\n\t\t * IE浏览器下：tempArr2={filename,\"E:\\snmp4j--api.zip\"}\r\n\t\t */\r\n\t\tString[] tempArr2 = tempArr1[2].split(\"=\");\r\n\t\t// 获取文件名，兼容各种浏览器的写法\r\n\t\tString fileName = tempArr2[1].substring(tempArr2[1].lastIndexOf(\"\\\\\") + 1).replaceAll(\"\\\"\", \"\");\r\n\t\treturn fileName;\r\n\t}\r\n\t\r\n}\r\n```\r\n\r\n\r\n\r\n15. 普通用户修改密码功能\r\n\r\n![](Img/11.png)\r\n\r\n+ 核心代码\r\n\r\n```java\r\nString update_user_sql=\"UPDATE tickets_user SET USER_PASSWORD =? WHERE\tUSER_ID =?\";\r\n```\r\n\r\n\r\n\r\n#### 拓展知识\r\n\r\n1. [mysql Navicat12约束条件的设置和详解](https://blog.csdn.net/qq_34168515/article/details/108186202)\r\n2. [navicat表约束怎么弄](https://www.php.cn/tool/navicat/428197.html)\r\n2. [**Java过滤器Filter使用详解**](https://cloud.tencent.com/developer/article/1084375)\r\n2. [java之Cookie具体解释](https://www.cnblogs.com/lytwajue/p/7243006.html)\r\n2. [java读取和写入浏览器Cookies](https://www.cnblogs.com/MaxElephant/p/8250666.html)\r\n2. [Java Session 详解](http://www.codebaoku.com/it-java/it-java-224930.html)\r\n2. [谷歌浏览器控制台 f12怎么设置成中文/英文 切换方法，一定要看到最后！！！](https://www.cnblogs.com/sinberya/p/16408606.html)\r\n2. [JSP 中EL表达式用法详解](https://www.cnblogs.com/czs1982/p/3966748.html)\r\n2. [Jsp核心标签库的运用](https://how2j.cn/k/jsp/jsp-jstl/578.html)\r\n2. [**navicat如何导出mysql数据表结构**](https://blog.51cto.com/u_15127600/4187552)\r\n2. [解决向github提交代码不用输入帐号密码](https://segmentfault.com/a/1190000008435592)\r\n2. [Git 报错 Updates were rejected because the remote contains work that you do](https://blog.csdn.net/liulei952413829/article/details/117553977)\r\n2. [解决Updates were rejected because the remote contains work that you do](https://blog.csdn.net/m0_51715325/article/details/121789720)\r\n2. [【解决】Merge branch 'master' of https://gitee.com/](https://blog.csdn.net/mus123/article/details/104201106)\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavaobjects%2Ftickets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjavaobjects%2Ftickets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavaobjects%2Ftickets/lists"}