[{"data":1,"prerenderedAt":1668},["ShallowReactive",2],{"article-backend\u002Ftomcat-servlet":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":13,"_type":1662,"_id":1663,"_source":1664,"_file":1665,"_stem":1666,"_extension":1667},"\u002Farticles\u002Fbackend\u002Ftomcat-servlet","backend",false,"","Tomcat + Servlet 基础入门：从环境搭建到请求响应全解析","系统讲解 Tomcat 服务器配置与启动、Servlet 开发与部署、生命周期管理、线程安全及 Request\u002FResponse\u002FCookie\u002FSession\u002FServletContext 等核心对象的使用方法。","2023-03-23",[12],"软件工程",{"type":14,"children":15,"toc":1648},"root",[16,24,29,34,39,44,49,56,65,71,76,81,88,193,198,280,285,294,299,322,369,374,381,387,395,400,405,428,435,441,462,468,489,529,535,556,563,592,598,634,640,648,760,764,771,776,784,790,796,804,811,817,830,840,850,858,863,871,876,884,936,944,973,978,986,992,1000,1006,1014,1020,1028,1034,1040,1066,1071,1079,1084,1092,1100,1105,1113,1121,1128,1133,1141,1149,1157,1165,1171,1179,1187,1195,1201,1224,1230,1238,1246,1252,1260,1266,1274,1292,1300,1318,1324,1330,1338,1351,1357,1365,1372,1379,1392,1397,1403,1411,1416,1424,1429,1437,1442,1450,1455,1468,1476,1489,1495,1503,1511,1519,1527,1534,1539,1547,1552,1560,1568,1576,1584,1592,1600,1608,1616,1624,1630],{"type":17,"tag":18,"props":19,"children":20},"element","p",{},[21],{"type":22,"value":23},"text","jdbc是后端与数据库的交互",{"type":17,"tag":18,"props":25,"children":26},{},[27],{"type":22,"value":28},"Tomcat + Servlet是客户端与后端（服务端）的交互",{"type":17,"tag":18,"props":30,"children":31},{},[32],{"type":22,"value":33},"Tomcat开启web服务器，Servlet根据请求路径进行动态资源分发",{"type":17,"tag":18,"props":35,"children":36},{},[37],{"type":22,"value":38},"Tomcat实现给客户端呈现静态页面",{"type":17,"tag":18,"props":40,"children":41},{},[42],{"type":22,"value":43},"Tomcat + Servlet实现根据客户端请求的资源地址和请求方法响应不同的页面",{"type":17,"tag":18,"props":45,"children":46},{},[47],{"type":22,"value":48},"JDBC + Tomcat + Servlet实现根据客户端请求的资源地址和请求方法响应不同的页面，并且可以去数据库去请求数据",{"type":17,"tag":50,"props":51,"children":53},"h2",{"id":52},"tomcat",[54],{"type":22,"value":55},"Tomcat",{"type":17,"tag":18,"props":57,"children":58},{},[59],{"type":17,"tag":60,"props":61,"children":64},"img",{"alt":62,"src":63},"image.png","https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F2a128c6c13e945ebbabb8384510e264c~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":66,"props":67,"children":69},"h3",{"id":68},"简介",[70],{"type":22,"value":68},{"type":17,"tag":18,"props":72,"children":73},{},[74],{"type":22,"value":75},"Tomcat是Apache开源组织共享的Jakarta项目中的一个核心项目，Tomcat开源免费、支持Java中的动态网页技术Servlet和JAP规范，因此Java开发者多使用Tomcat",{"type":17,"tag":18,"props":77,"children":78},{},[79],{"type":22,"value":80},"Tomcat在企业主流使用8.5和9，我们的学习主要基于8.5.72版本；各个版本之间的最大区别就是对于JavaEE版本及Servlet规范的支持、依赖的JDK版本。Tomcat8.x全面支持Servlet3.x规范及JavaEE4规范",{"type":17,"tag":82,"props":83,"children":85},"h4",{"id":84},"tomcat的目录结构",[86],{"type":22,"value":87},"Tomcat的目录结构",{"type":17,"tag":89,"props":90,"children":91},"ul",{},[92,109,123,137,151,165,179],{"type":17,"tag":93,"props":94,"children":95},"li",{},[96,107],{"type":17,"tag":97,"props":98,"children":99},"strong",{},[100],{"type":17,"tag":101,"props":102,"children":104},"code",{"className":103},[],[105],{"type":22,"value":106},"bin：",{"type":22,"value":108}," 存放可执行二进制文件（startup.bat用于启动Tomcat、shutdown.bat用于停止Tomcat）",{"type":17,"tag":93,"props":110,"children":111},{},[112,121],{"type":17,"tag":97,"props":113,"children":114},{},[115],{"type":17,"tag":101,"props":116,"children":118},{"className":117},[],[119],{"type":22,"value":120},"conf:",{"type":22,"value":122}," 存放Tomcat的配置文件（server.xml可以配置Tomcat的端口，web.xml）",{"type":17,"tag":93,"props":124,"children":125},{},[126,135],{"type":17,"tag":97,"props":127,"children":128},{},[129],{"type":17,"tag":101,"props":130,"children":132},{"className":131},[],[133],{"type":22,"value":134},"lib：",{"type":22,"value":136}," 存放Tomcat服务器运行web项目所需的基础类库",{"type":17,"tag":93,"props":138,"children":139},{},[140,149],{"type":17,"tag":97,"props":141,"children":142},{},[143],{"type":17,"tag":101,"props":144,"children":146},{"className":145},[],[147],{"type":22,"value":148},"logs：",{"type":22,"value":150}," 存放了Tomcat服务器运行日志、记录了服务器启动、运行异常及关闭等操作的记录",{"type":17,"tag":93,"props":152,"children":153},{},[154,163],{"type":17,"tag":97,"props":155,"children":156},{},[157],{"type":17,"tag":101,"props":158,"children":160},{"className":159},[],[161],{"type":22,"value":162},"temp：",{"type":22,"value":164}," 临时目录，存放Tomcat运行过程中产生的临时文件",{"type":17,"tag":93,"props":166,"children":167},{},[168,177],{"type":17,"tag":97,"props":169,"children":170},{},[171],{"type":17,"tag":101,"props":172,"children":174},{"className":173},[],[175],{"type":22,"value":176},"webapps：",{"type":22,"value":178}," 存放Tomcat管理的web项目的目录，此目录中默认部署了Tomcat管理器等几个web项目",{"type":17,"tag":93,"props":180,"children":181},{},[182,191],{"type":17,"tag":97,"props":183,"children":184},{},[185],{"type":17,"tag":101,"props":186,"children":188},{"className":187},[],[189],{"type":22,"value":190},"work:",{"type":22,"value":192}," Tomcat可以运行动态网页，动态网页就是在服务器上将数据加载到网页生成的页面，次目录就是存放Tomcat生成的文件",{"type":17,"tag":66,"props":194,"children":196},{"id":195},"启动",[197],{"type":22,"value":195},{"type":17,"tag":199,"props":200,"children":201},"ol",{},[202,230,256],{"type":17,"tag":93,"props":203,"children":204},{},[205,207,212,214,220,222,228],{"type":22,"value":206},"进入",{"type":17,"tag":101,"props":208,"children":210},{"className":209},[],[211],{"type":22,"value":52},{"type":22,"value":213},"的",{"type":17,"tag":101,"props":215,"children":217},{"className":216},[],[218],{"type":22,"value":219},"bin",{"type":22,"value":221},"目录：",{"type":17,"tag":101,"props":223,"children":225},{"className":224},[],[226],{"type":22,"value":227},"cd \u002FLibrary\u002FTomcat\u002Fbin",{"type":22,"value":229}," 或者打开Tomcat文件夹，把bin文件夹直接拖拉到终端，当然前提是先输入cd+空格",{"type":17,"tag":93,"props":231,"children":232},{},[233,235,241,250,254],{"type":22,"value":234},"启动服务：",{"type":17,"tag":101,"props":236,"children":238},{"className":237},[],[239],{"type":22,"value":240},"sudo sh .\u002Fstartup.sh",{"type":17,"tag":242,"props":243,"children":245},"pre",{"code":244},"Using CATALINA_BASE:   \u002FLibrary\u002FTomcat\nUsing CATALINA_HOME:   \u002FLibrary\u002FTomcat\nUsing CATALINA_TMPDIR: \u002FLibrary\u002FTomcat\u002Ftemp\nUsing JRE_HOME:        \u002FLibrary\u002FJava\u002FJavaVirtualMachines\u002Fjdk-18.0.2.1.jdk\u002FContents\u002FHome\nUsing CLASSPATH:       \u002FLibrary\u002FTomcat\u002Fbin\u002Fbootstrap.jar:\u002FLibrary\u002FTomcat\u002Fbin\u002Ftomcat-juli.jar\nUsing CATALINA_OPTS:\nTomcat started.\n",[246],{"type":17,"tag":101,"props":247,"children":248},{"__ignoreMap":7},[249],{"type":22,"value":244},{"type":17,"tag":251,"props":252,"children":253},"br",{},[],{"type":22,"value":255},"出现这个就代表启动成功",{"type":17,"tag":93,"props":257,"children":258},{},[259,261,267,275,278],{"type":22,"value":260},"关闭服务：",{"type":17,"tag":101,"props":262,"children":264},{"className":263},[],[265],{"type":22,"value":266},"sh .\u002Fshutdown.sh",{"type":17,"tag":242,"props":268,"children":270},{"code":269},"Using CATALINA_BASE:   \u002FLibrary\u002FTomcat\nUsing CATALINA_HOME:   \u002FLibrary\u002FTomcat\nUsing CATALINA_TMPDIR: \u002FLibrary\u002FTomcat\u002Ftemp\nUsing JRE_HOME:        \u002FLibrary\u002FJava\u002FJavaVirtualMachines\u002Fjdk-18.0.2.1.jdk\u002FContents\u002FHome\nUsing CLASSPATH:       \u002FLibrary\u002FTomcat\u002Fbin\u002Fbootstrap.jar:\u002FLibrary\u002FTomcat\u002Fbin\u002Ftomcat-juli.jar\nUsing CATALINA_OPTS:   \nNOTE: Picked up JDK_JAVA_OPTIONS:  --add-opens=java.base\u002Fjava.lang=ALL-UNNAMED --add-opens=java.base\u002Fjava.io=ALL-UNNAMED --add-opens=java.base\u002Fjava.util=ALL-UNNAMED --add-opens=java.base\u002Fjava.util.concurrent=ALL-UNNAMED --add-opens=java.rmi\u002Fsun.rmi.transport=ALL-UNNAMED\n",[271],{"type":17,"tag":101,"props":272,"children":273},{"__ignoreMap":7},[274],{"type":22,"value":269},{"type":17,"tag":251,"props":276,"children":277},{},[],{"type":22,"value":279},"出现这个就代表关闭成功",{"type":17,"tag":66,"props":281,"children":283},{"id":282},"web项目部署",[284],{"type":22,"value":282},{"type":17,"tag":286,"props":287,"children":288},"blockquote",{},[289],{"type":17,"tag":18,"props":290,"children":291},{},[292],{"type":22,"value":293},"web项目部署：将web项目交给Tomcat管理，当用户访问Tomcat时，Tomcat可以将web项目中的资源响应给用户浏览器",{"type":17,"tag":18,"props":295,"children":296},{},[297],{"type":22,"value":298},"方法：直接将web项目拷贝到Tomcat的webapps目录",{"type":17,"tag":18,"props":300,"children":301},{},[302,304,312,314,320],{"type":22,"value":303},"打开网站：",{"type":17,"tag":305,"props":306,"children":310},"a",{"href":307,"rel":308},"http:\u002F\u002Fhost-ip:tomcat-port\u002Fweb-Path\u002F",[309],"nofollow",[311],{"type":22,"value":307},{"type":22,"value":313}," (test地址：",{"type":17,"tag":305,"props":315,"children":318},{"href":316,"rel":317},"http:\u002F\u002Flocalhost:8080\u002Ftest\u002Findex.html",[309],[319],{"type":22,"value":316},{"type":22,"value":321},")",{"type":17,"tag":89,"props":323,"children":324},{},[325,336,347,358],{"type":17,"tag":93,"props":326,"children":327},{},[328,334],{"type":17,"tag":101,"props":329,"children":331},{"className":330},[],[332],{"type":22,"value":333},"http:\u002F\u002F",{"type":22,"value":335},"：web服务的htpp传输协议",{"type":17,"tag":93,"props":337,"children":338},{},[339,345],{"type":17,"tag":101,"props":340,"children":342},{"className":341},[],[343],{"type":22,"value":344},"host-ip",{"type":22,"value":346},"：服务器所在计算机的IP",{"type":17,"tag":93,"props":348,"children":349},{},[350,356],{"type":17,"tag":101,"props":351,"children":353},{"className":352},[],[354],{"type":22,"value":355},"tomcat-port",{"type":22,"value":357},"：Tomcat服务器占用的网络端口（默认8080，可以在conf.server.xml中修改端口）",{"type":17,"tag":93,"props":359,"children":360},{},[361,367],{"type":17,"tag":101,"props":362,"children":364},{"className":363},[],[365],{"type":22,"value":366},"web-Path",{"type":22,"value":368},"：Tomcat中部署的web项目的访问路径",{"type":17,"tag":18,"props":370,"children":371},{},[372],{"type":22,"value":373},"示例图：",{"type":17,"tag":18,"props":375,"children":376},{},[377],{"type":17,"tag":60,"props":378,"children":380},{"alt":62,"src":379},"https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fd8f3de0b25d242e4909df5431808a216~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":50,"props":382,"children":384},{"id":383},"servlet",[385],{"type":22,"value":386},"Servlet",{"type":17,"tag":286,"props":388,"children":389},{},[390],{"type":17,"tag":18,"props":391,"children":392},{},[393],{"type":22,"value":394},"Servlet是服务器端的Java程序、能够接收HTTP请求、处理HTTP请求、并对HTTP请求进行相应的动态网页技术。",{"type":17,"tag":18,"props":396,"children":397},{},[398],{"type":22,"value":399},"Servlet是JavaEE（JavaWeb）规范的一个重要组成部分",{"type":17,"tag":18,"props":401,"children":402},{},[403],{"type":22,"value":404},"Servlet的作用：",{"type":17,"tag":89,"props":406,"children":407},{},[408,413,418,423],{"type":17,"tag":93,"props":409,"children":410},{},[411],{"type":22,"value":412},"接收客户端的HTTP请求（浏览器）",{"type":17,"tag":93,"props":414,"children":415},{},[416],{"type":22,"value":417},"根据用户请求进行数据处理",{"type":17,"tag":93,"props":419,"children":420},{},[421],{"type":22,"value":422},"动态生成网页（网页中的数据是根据客户端请求动态改变的）",{"type":17,"tag":93,"props":424,"children":425},{},[426],{"type":22,"value":427},"将生成的包含动态数据的网页响应给客户端",{"type":17,"tag":18,"props":429,"children":430},{},[431],{"type":17,"tag":60,"props":432,"children":434},{"alt":62,"src":433},"https:\u002F\u002Fp6-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F6f1fcae32304435cb32c37ccb568177f~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":66,"props":436,"children":438},{"id":437},"创建java-web工程",[439],{"type":22,"value":440},"创建Java Web工程",{"type":17,"tag":286,"props":442,"children":443},{},[444,449],{"type":17,"tag":18,"props":445,"children":446},{},[447],{"type":22,"value":448},"Servlet是JavaEE规范的一部分，Servlet的开发需要依赖JavaEE环境，之前创建的单纯的Java应用已经不能满足Serclet开发所需的环境需求，我们要创建Java Web工程",{"type":17,"tag":89,"props":450,"children":451},{},[452,457],{"type":17,"tag":93,"props":453,"children":454},{},[455],{"type":22,"value":456},"Java工程：只引入JDK的标准库（JavaSE）",{"type":17,"tag":93,"props":458,"children":459},{},[460],{"type":22,"value":461},"Java Web工程：引入了Java企业级开发环境（JavaEE）",{"type":17,"tag":82,"props":463,"children":465},{"id":464},"创建servlet类",[466],{"type":22,"value":467},"创建Servlet类",{"type":17,"tag":286,"props":469,"children":470},{},[471,476],{"type":17,"tag":18,"props":472,"children":473},{},[474],{"type":22,"value":475},"Servlet是一个java程序，是一个能够接收HTTP请求的Java类，因此需要实现HTTP请求",{"type":17,"tag":18,"props":477,"children":478},{},[479,481,487],{"type":22,"value":480},"在JavaEE库中有一个类",{"type":17,"tag":101,"props":482,"children":484},{"className":483},[],[485],{"type":22,"value":486},"javax.servlet.http.HttpServlet",{"type":22,"value":488},"实现了HTTP协议，我们创建的类只要继承这个HttpServlet类，就实现了HTTP协议，就能接受HTTP请求",{"type":17,"tag":199,"props":490,"children":492},{"start":491},0,[493,503,516],{"type":17,"tag":93,"props":494,"children":495},{},[496,498],{"type":22,"value":497},"创建一个类继承",{"type":17,"tag":101,"props":499,"children":501},{"className":500},[],[502],{"type":22,"value":486},{"type":17,"tag":93,"props":504,"children":505},{},[506,508,514],{"type":22,"value":507},"继承HttpServlet的类就能够接收HTTP请求，我们把这样的类称之为Servlet类，类似",{"type":17,"tag":101,"props":509,"children":511},{"className":510},[],[512],{"type":22,"value":513},"****Servlet",{"type":22,"value":515},"格式命名",{"type":17,"tag":93,"props":517,"children":518},{},[519,521,527],{"type":22,"value":520},"在我们创建的Servlet类中，重写",{"type":17,"tag":101,"props":522,"children":524},{"className":523},[],[525],{"type":22,"value":526},"doPost\u002FdoGet",{"type":22,"value":528},"用于处理用户不同的请求",{"type":17,"tag":82,"props":530,"children":532},{"id":531},"配置servlet类的url",[533],{"type":22,"value":534},"配置Servlet类的URL",{"type":17,"tag":286,"props":536,"children":537},{},[538,543],{"type":17,"tag":18,"props":539,"children":540},{},[541],{"type":22,"value":542},"Servlet创建完成之后，需要配置url访问路径，然后将web项目运行在Tomcat之上，就能够通过配重的url访问Servlet类。Servlet自3.0规范开始支持两种配置方式",{"type":17,"tag":89,"props":544,"children":545},{},[546,551],{"type":17,"tag":93,"props":547,"children":548},{},[549],{"type":22,"value":550},"基于web.xml配置文件进行配置",{"type":17,"tag":93,"props":552,"children":553},{},[554],{"type":22,"value":555},"基于注解配置",{"type":17,"tag":557,"props":558,"children":560},"h5",{"id":559},"基于webxml配置servlet",[561],{"type":22,"value":562},"基于web.xml配置Servlet",{"type":17,"tag":89,"props":564,"children":565},{},[566,579],{"type":17,"tag":93,"props":567,"children":568},{},[569,571,577],{"type":22,"value":570},"打开Java Web工程中",{"type":17,"tag":101,"props":572,"children":574},{"className":573},[],[575],{"type":22,"value":576},"web\u002FWEB_INF\u002Fweb.xml",{"type":22,"value":578},"文件",{"type":17,"tag":93,"props":580,"children":581},{},[582,584],{"type":22,"value":583},"配置如下",{"type":17,"tag":242,"props":585,"children":587},{"code":586},"\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\u003Cweb-app xmlns=\"http:\u002F\u002Fxmlns.jcp.org\u002Fxml\u002Fns\u002Fjavaee\"\n         xmlns:xsi=\"http:\u002F\u002Fwww.w3.org\u002F2001\u002FXMLSchema-instance\"\n         xsi:schemaLocation=\"http:\u002F\u002Fxmlns.jcp.org\u002Fxml\u002Fns\u002Fjavaee http:\u002F\u002Fxmlns.jcp.org\u002Fxml\u002Fns\u002Fjavaee\u002Fweb-app_4_0.xsd\"\n         version=\"4.0\">\n​\n    \u003C!--  servlet标签：配置类标签  -->\n    \u003Cservlet>\n        \u003Cservlet-name>BookListServlet\u003C\u002Fservlet-name>\n        \u003Cservlet-class>com.example.learnservlet.BookListServlet\u003C\u002Fservlet-class>\n    \u003C\u002Fservlet>\n \n    \u003C!--servlet-mapping标签：配置url-->\n    \u003Cservlet-mapping>\n        \u003C!--  通过name与上面servlet标签进行匹配，展示响应的类-->\n        \u003Cservlet-name>BookListServlet\u003C\u002Fservlet-name>\n        \u003C!--  用户通过此url来访问对应的类  -->\n        \u003Curl-pattern>\u002Fbook-list\u003C\u002Furl-pattern>\n    \u003C\u002Fservlet-mapping>\n\u003C\u002Fweb-app>\n",[588],{"type":17,"tag":101,"props":589,"children":590},{"__ignoreMap":7},[591],{"type":22,"value":586},{"type":17,"tag":557,"props":593,"children":595},{"id":594},"基于注解配置servlet",[596],{"type":22,"value":597},"基于注解配置Servlet",{"type":17,"tag":89,"props":599,"children":600},{},[601,622],{"type":17,"tag":93,"props":602,"children":603},{},[604,606,612,614,620],{"type":22,"value":605},"在创建的Servlet类上添加",{"type":17,"tag":101,"props":607,"children":609},{"className":608},[],[610],{"type":22,"value":611},"@WebServlet",{"type":22,"value":613},"注解，在注解后的参数中配置url，url也必须是以",{"type":17,"tag":101,"props":615,"children":617},{"className":616},[],[618],{"type":22,"value":619},"\u002F",{"type":22,"value":621},"开头",{"type":17,"tag":93,"props":623,"children":624},{},[625,626],{"type":22,"value":583},{"type":17,"tag":242,"props":627,"children":629},{"code":628},"\u002F\u002F 注解\n@WebServlet(\"\u002Fbook-query\")\npublic class BookQueryServlet extends HttpServlet {\n​\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        \u002F\u002F super.doGet(req, resp);\n        System.out.println(\"BookQueryServlet===========doGet\");\n    }\n​\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        \u002F\u002F super.doPost(req, resp);\n        System.out.println(\"BookQueryServlet===========doPost\");\n    }\n  \n}\n",[630],{"type":17,"tag":101,"props":631,"children":632},{"__ignoreMap":7},[633],{"type":22,"value":628},{"type":17,"tag":82,"props":635,"children":637},{"id":636},"idea部署web项目",[638],{"type":22,"value":639},"IDEA部署web项目",{"type":17,"tag":286,"props":641,"children":642},{},[643],{"type":17,"tag":18,"props":644,"children":645},{},[646],{"type":22,"value":647},"IDEA版本：2022.2",{"type":17,"tag":199,"props":649,"children":650},{},[651,663,675,687,699,725],{"type":17,"tag":93,"props":652,"children":653},{},[654,656,659],{"type":22,"value":655},"配置项目",{"type":17,"tag":251,"props":657,"children":658},{},[],{"type":17,"tag":60,"props":660,"children":662},{"alt":62,"src":661},"https:\u002F\u002Fp1-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F05ca05b138804d18ae8fae36d8073045~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":93,"props":664,"children":665},{},[666,668,671],{"type":22,"value":667},"部署项目",{"type":17,"tag":251,"props":669,"children":670},{},[],{"type":17,"tag":60,"props":672,"children":674},{"alt":62,"src":673},"https:\u002F\u002Fp3-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Ffc1c0358fa2542e0b81d62dde42bb574~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":93,"props":676,"children":677},{},[678,680,683],{"type":22,"value":679},"配置web项目的访问路径",{"type":17,"tag":251,"props":681,"children":682},{},[],{"type":17,"tag":60,"props":684,"children":686},{"alt":62,"src":685},"https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fb2cb26f6bf1244f8ae48ebe77139d872~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":93,"props":688,"children":689},{},[690,692,695],{"type":22,"value":691},"添加展示的页面",{"type":17,"tag":251,"props":693,"children":694},{},[],{"type":17,"tag":60,"props":696,"children":698},{"alt":62,"src":697},"https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F8e047ac0021241ae98678ae804066822~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":93,"props":700,"children":701},{},[702,704],{"type":22,"value":703},"启动Tomcat",{"type":17,"tag":286,"props":705,"children":706},{},[707,712],{"type":17,"tag":18,"props":708,"children":709},{},[710],{"type":22,"value":711},"点击IDEA启动按钮即可",{"type":17,"tag":89,"props":713,"children":714},{},[715,720],{"type":17,"tag":93,"props":716,"children":717},{},[718],{"type":22,"value":719},"播放按钮：直接运行",{"type":17,"tag":93,"props":721,"children":722},{},[723],{"type":22,"value":724},"甲壳虫：debug运行",{"type":17,"tag":93,"props":726,"children":727},{},[728,730],{"type":22,"value":729},"Tomcat启动完成",{"type":17,"tag":89,"props":731,"children":732},{},[733,738,743,747],{"type":17,"tag":93,"props":734,"children":735},{},[736],{"type":22,"value":737},"构建web项目",{"type":17,"tag":93,"props":739,"children":740},{},[741],{"type":22,"value":742},"将web项目拷贝到Tomcat",{"type":17,"tag":93,"props":744,"children":745},{},[746],{"type":22,"value":703},{"type":17,"tag":93,"props":748,"children":749},{},[750,752,758],{"type":22,"value":751},"打开浏览器，访问当前项目首页（如：",{"type":17,"tag":305,"props":753,"children":756},{"href":754,"rel":755},"http:\u002F\u002Flocalhost:8080\u002Fdemo1\u002Fbook-list",[309],[757],{"type":22,"value":754},{"type":22,"value":759},"）",{"type":17,"tag":18,"props":761,"children":762},{},[763],{"type":22,"value":373},{"type":17,"tag":18,"props":765,"children":766},{},[767],{"type":17,"tag":60,"props":768,"children":770},{"alt":62,"src":769},"https:\u002F\u002Fp1-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F5f808dc099a94197a4c6e251bfbda9f7~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":82,"props":772,"children":774},{"id":773},"响应给客户端数据",[775],{"type":22,"value":773},{"type":17,"tag":242,"props":777,"children":779},{"code":778},"@WebServlet(\"\u002Fbook-query\")\npublic class BookQueryServlet extends HttpServlet {\n​\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        \u002F\u002F super.doGet(req, resp);\n        System.out.println(\"BookQueryServlet===========doGet\");\n​\n        \u002F\u002F 1. 接收到浏览器请求时传递的图书ID（bookId）\n        String bookId = req.getParameter(\"bookId\");\n​\n        \u002F\u002F 2. 根据bid查询数据库图书编（伪代码）\n        Map\u003CString, Book> bookMap = new HashMap\u003C>();\n        bookMap.put(\"1001\", new Book(\"1001\", \"Java\", \"张三\", 111.2, \"\u002Fsrc\"));\n        bookMap.put(\"1002\", new Book(\"1002\", \"JavaScript\", \"李四\", 110.2, \"\u002Fsrc\"));\n        bookMap.put(\"1003\", new Book(\"1003\", \"Go\", \"王五\", 210.2, \"\u002Fsrc\"));\n​\n        Book book = bookMap.get(bookId);\n        System.out.println(book.getBookAuthor());\n        \u002F\u002F 3. 将网页响应给浏览器\n        PrintWriter writer = resp.getWriter();\n        writer.println(book.getBookId() + \"  bookId\");\n        writer.println(book.getBookName() + \"   bookName\");\n        writer.println(book.getBookAuthor() + \"  bookAuthor\");\n        writer.println(book.getBookPrice() + \"   bookPrice\");\n        writer.println(book.getBookImgPath() + \"   bookImgPath\");\n        writer.flush();\n        writer.close();\n    }\n​\n    @Override\n    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        \u002F\u002F super.doPost(req, resp);\n        System.out.println(\"BookQueryServlet===========doPost\");\n    }\n}\n",[780],{"type":17,"tag":101,"props":781,"children":782},{"__ignoreMap":7},[783],{"type":22,"value":778},{"type":17,"tag":66,"props":785,"children":787},{"id":786},"servlet原理解析",[788],{"type":22,"value":789},"Servlet原理解析",{"type":17,"tag":82,"props":791,"children":793},{"id":792},"servlet响应流程",[794],{"type":22,"value":795},"Servlet响应流程",{"type":17,"tag":286,"props":797,"children":798},{},[799],{"type":17,"tag":18,"props":800,"children":801},{},[802],{"type":22,"value":803},"Servlet是Tomcat上的一个资源",{"type":17,"tag":18,"props":805,"children":806},{},[807],{"type":17,"tag":60,"props":808,"children":810},{"alt":62,"src":809},"https:\u002F\u002Fp3-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fe668014a438646cc80f9b30ede6dc8dc~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":82,"props":812,"children":814},{"id":813},"servlet实例的生命周期",[815],{"type":22,"value":816},"Servlet实例的生命周期",{"type":17,"tag":286,"props":818,"children":819},{},[820,825],{"type":17,"tag":18,"props":821,"children":822},{},[823],{"type":22,"value":824},"当客户端的请求到达Tomcat，Tomcat会创建一个线程来接收、处理、响应客户端请求，客户端在请求某个Servlet类时，线程需要通过这个Servlet类的实例来调用Servlet方法，调用doGet\u002FdoPost...方法来处理响应请求，最后调用destroy销毁实例",{"type":17,"tag":18,"props":826,"children":827},{},[828],{"type":22,"value":829},"servlet实例的生命周期的是一个Servlet类的实例从创建到销毁的过程：加载 ==> 初始化 ==> 服务 ==> 销毁",{"type":17,"tag":18,"props":831,"children":832},{},[833,838],{"type":17,"tag":97,"props":834,"children":835},{},[836],{"type":22,"value":837},"加载：",{"type":22,"value":839}," 用户请求Servlet的时候，Servlet容器会检查是否已经加载并实例化该Servlet类，如果没有就会加载并初始化Servlet类。",{"type":17,"tag":18,"props":841,"children":842},{},[843,848],{"type":17,"tag":97,"props":844,"children":845},{},[846],{"type":22,"value":847},"初始化：",{"type":22,"value":849}," Servlet实例创建成功，Servlet容器就会调用Serlvet的init方法，在这个方法中，Servlet可以做一些初始化的事情，如：读取配置文件，连接数据库，创建数据库连接池。",{"type":17,"tag":18,"props":851,"children":852},{},[853],{"type":17,"tag":97,"props":854,"children":855},{},[856],{"type":22,"value":857},"服务：",{"type":17,"tag":18,"props":859,"children":860},{},[861],{"type":22,"value":862},"请求到达Servlet，容器就会调用Servlet的service方法，在这个方法中，Servlet可以根据请求方法去调用不同的方法，如：doGet\u002FdoPost。，然后生成相应的响应。",{"type":17,"tag":18,"props":864,"children":865},{},[866],{"type":17,"tag":97,"props":867,"children":868},{},[869],{"type":22,"value":870},"销毁：",{"type":17,"tag":18,"props":872,"children":873},{},[874],{"type":22,"value":875},"当关闭服务器时，容器就是调用Servlet上的destroy方法，用来销毁Servlet实例，在这个方法中，可以用来做一些收尾的工作，比如：释放资源、关闭数据库连接、关闭线程等。",{"type":17,"tag":242,"props":877,"children":879},{"code":878},"public class BookListServlet extends HttpServlet {\n  \n    \u002F\u002F 初始化\n    @Override\n    public void init(ServletConfig config) throws ServletException {\n        System.out.println(\"初始化Servlet\");\n        super.init(config);\n    }\n      \n    \u002F\u002F 2. 服务 GenericServlet类上的\n    @Override\n    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {\n        super.service(req, res);\n    }\n​\n    \u002F\u002F 3. 服务 HttpServlet类上的\n    @Override\n    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        super.service(req, resp);\n    }\n​\n    \u002F\u002F 4. 处理请求\n    @Override\n    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n        \u002F\u002F 在这里可以进行jdbc的数据库操作\n        System.out.println(\"BookListServlet==========doGet\");\n    }\n  \n    \u002F\u002F  5. 销毁\n    @Override\n    public void destroy() {\n        System.out.println(\"实例被销毁了\");\n    }\n}\n",[880],{"type":17,"tag":101,"props":881,"children":882},{"__ignoreMap":7},[883],{"type":22,"value":878},{"type":17,"tag":199,"props":885,"children":886},{"start":491},[887,892,915],{"type":17,"tag":93,"props":888,"children":889},{},[890],{"type":22,"value":891},"Servlet类是单实例多线程的，一个Servlet类自始至终只会创建一个对象",{"type":17,"tag":93,"props":893,"children":894},{},[895,897,902,908,910,913],{"type":22,"value":896},"如果当前Servlet类",{"type":17,"tag":97,"props":898,"children":899},{},[900],{"type":22,"value":901},"没有配置",{"type":17,"tag":101,"props":903,"children":905},{"className":904},[],[906],{"type":22,"value":907},"\u003Cload-on-startup>1\u003C\u002Fload-on-startup>",{"type":22,"value":909},"：",{"type":17,"tag":251,"props":911,"children":912},{},[],{"type":22,"value":914},"当客户端第一次请求Servlet时，创建当前Servlet类的实例，然后使用这个实例调用service(ServletRequest、ServletResponse)方法--service(HttpServletRequest、HttpServletResponse)方法--doGet\u002FdoPost处理客户端请求；当客户端请求再次到达时将不会重新创建Servlet实力，直接视同第一次创建的实例调用方法进行响应",{"type":17,"tag":93,"props":916,"children":917},{},[918,919,929,931,934],{"type":22,"value":896},{"type":17,"tag":97,"props":920,"children":921},{},[922,924],{"type":22,"value":923},"配置了",{"type":17,"tag":101,"props":925,"children":927},{"className":926},[],[928],{"type":22,"value":907},{"type":22,"value":930}," ：",{"type":17,"tag":251,"props":932,"children":933},{},[],{"type":22,"value":935},"当服务器启动时就会创建Servlet类的实例，无论客户端是第一次请求这个Servlet类，还是再次请求都不会创建Servlet类实例，直接使用服务器启动时创建的Servlet实例来接收、处理、响应客户端请求",{"type":17,"tag":18,"props":937,"children":938},{},[939],{"type":17,"tag":97,"props":940,"children":941},{},[942],{"type":22,"value":943},"配置load-on-startup的两种方式：",{"type":17,"tag":89,"props":945,"children":946},{},[947,960],{"type":17,"tag":93,"props":948,"children":949},{},[950,952],{"type":22,"value":951},"xml配置",{"type":17,"tag":242,"props":953,"children":955},{"code":954},"\u003C!--  servlet标签：配置类标签  -->\n\u003Cservlet>\n    \u003Cservlet-name>BookListServlet\u003C\u002Fservlet-name>\n    \u003Cservlet-class>com.example.learnservlet.BookListServlet\u003C\u002Fservlet-class>\n    \u003C!-- 如果有多个Serlvet都配置了load-on-startup，里面的数字就是在服务器中创建实例的顺序-->\n    \u003Cload-on-startup>1\u003C\u002Fload-on-startup>\n\u003C\u002Fservlet>\n​\n\u003C!--servlet-mapping标签：配置url-->\n\u003Cservlet-mapping>\n    \u003C!--  通过name与上面servlet标签进行匹配，展示响应的类-->\n    \u003Cservlet-name>BookListServlet\u003C\u002Fservlet-name>\n    \u003C!--  用户通过此url来访问对应的类  -->\n    \u003Curl-pattern>\u002Fbook-list\u003C\u002Furl-pattern>\n\u003C\u002Fservlet-mapping>\n",[956],{"type":17,"tag":101,"props":957,"children":958},{"__ignoreMap":7},[959],{"type":22,"value":954},{"type":17,"tag":93,"props":961,"children":962},{},[963,965],{"type":22,"value":964},"注解配置",{"type":17,"tag":242,"props":966,"children":968},{"code":967},"@WebServlet(value = \"\u002Fbook-query\",loadOnStartup = 1)\n",[969],{"type":17,"tag":101,"props":970,"children":971},{"__ignoreMap":7},[972],{"type":22,"value":967},{"type":17,"tag":82,"props":974,"children":976},{"id":975},"线程安全问题",[977],{"type":22,"value":975},{"type":17,"tag":286,"props":979,"children":980},{},[981],{"type":17,"tag":18,"props":982,"children":983},{},[984],{"type":22,"value":985},"因为Servlet实例是单例模式，当多个客户端并发访问同一个Servlet类时，Tomcat会创建多个线程，多个线程会使用同一个Servlet实例，有可能会导致线程安全问题",{"type":17,"tag":557,"props":987,"children":989},{"id":988},"方案一实现singlethreadmode接口",[990],{"type":22,"value":991},"方案一：实现SingleThreadMode接口",{"type":17,"tag":286,"props":993,"children":994},{},[995],{"type":17,"tag":18,"props":996,"children":997},{},[998],{"type":22,"value":999},"我们可以让Servlet类实现SingleThreadMode接口，每个线程都会创建servlet实例，避免了多线程使用通过Servlet实例的请求，但是使用这种方式会导致对客户端的请求响应效率变低，增加了服务器因频繁创建和销毁Serlvet实例的开销，因为此种方式不建议使用，已经过时",{"type":17,"tag":557,"props":1001,"children":1003},{"id":1002},"方案二使用syncchron同步锁",[1004],{"type":22,"value":1005},"方案二：使用syncchron同步锁",{"type":17,"tag":242,"props":1007,"children":1009},{"code":1008},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n    synchronized (this) {\n        \u002F\u002F 业务代码\n    }\n}\n",[1010],{"type":17,"tag":101,"props":1011,"children":1012},{"__ignoreMap":7},[1013],{"type":22,"value":1008},{"type":17,"tag":557,"props":1015,"children":1017},{"id":1016},"建议在servlet实例中尽量不使用成员变量",[1018],{"type":22,"value":1019},"建议：在Servlet实例中尽量不使用成员变量",{"type":17,"tag":286,"props":1021,"children":1022},{},[1023],{"type":17,"tag":18,"props":1024,"children":1025},{},[1026],{"type":22,"value":1027},"如果将变量定义为成员变量，则这个变量在多个线程中是共享的，就有可能因为多个线程同时修改这个变量导致并发问题，因此我们可以将变量定义在处理业务的doXxx方法中，定义为局部变量之后，每个线程都有属于自己的局部变量",{"type":17,"tag":66,"props":1029,"children":1031},{"id":1030},"servlet开发技术",[1032],{"type":22,"value":1033},"Servlet开发技术",{"type":17,"tag":82,"props":1035,"children":1037},{"id":1036},"request对象",[1038],{"type":22,"value":1039},"Request对象",{"type":17,"tag":286,"props":1041,"children":1042},{},[1043,1056,1061],{"type":17,"tag":18,"props":1044,"children":1045},{},[1046,1048,1054],{"type":22,"value":1047},"也就是",{"type":17,"tag":101,"props":1049,"children":1051},{"className":1050},[],[1052],{"type":22,"value":1053},"(HttpServletRequest)",{"type":22,"value":1055},"对象",{"type":17,"tag":18,"props":1057,"children":1058},{},[1059],{"type":22,"value":1060},"我们在Servlet类中的doGet\u002FdoPost\u002FdoXxx方法中通过request对象接收客户端请求信息",{"type":17,"tag":18,"props":1062,"children":1063},{},[1064],{"type":22,"value":1065},"客户端向服务器发送的请求信息都会被封装到request对象，request(HttpServeltRequest类)提供了多个方法可以用于获取http请求中的数据",{"type":17,"tag":557,"props":1067,"children":1069},{"id":1068},"get请求",[1070],{"type":22,"value":1068},{"type":17,"tag":242,"props":1072,"children":1074},{"code":1073},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n    System.out.println(\"get请求\");\n​\n    \u002F* 获取请求行数据 *\u002F\n    \u002F\u002F 获取请求方法\n    String method = req.getMethod();\n    \u002F\u002F 获取请求url\n    String requestURI = req.getRequestURI();\n    \u002F\u002F 获取请求行中url参数，根据参数的key获取参数的value\n    String k1 = req.getParameter(\"k1\");\n    \u002F\u002F 获取客户端提交数据的协议及版本\n    String protocol = req.getProtocol();\n​\n    \u002F* 获取请求头数据 *\u002F\n    \u002F\u002F 获取请求头中所有key\n    Enumeration\u003CString> headerNames = req.getHeaderNames();\n    while (headerNames.hasMoreElements()) {\n        String key = headerNames.nextElement();\n        String header = req.getHeader(key);\n​\n        \u002F\u002F 打印结果\n        System.out.println(\"key\" + key);\n        System.out.println(\"header\" + header);\n    }\n​\n    \u002F\u002F 打印结果\n    System.out.println(\"getMethod======\" + method);  \u002F\u002F getMethod======GET\n    System.out.println(\"getRequestURI======\" + requestURI);  \u002F\u002F getRequestURI======\u002Fdemo1\u002Ftest\n    System.out.println(\"getParameter======\" + k1);  \u002F\u002F getParameter======v1\n    System.out.println(\"getProtocol======\" + protocol);  \u002F\u002F getProtocol======HTTP\u002F1.1s\n}\n",[1075],{"type":17,"tag":101,"props":1076,"children":1077},{"__ignoreMap":7},[1078],{"type":22,"value":1073},{"type":17,"tag":557,"props":1080,"children":1082},{"id":1081},"post请求",[1083],{"type":22,"value":1081},{"type":17,"tag":286,"props":1085,"children":1086},{},[1087],{"type":17,"tag":18,"props":1088,"children":1089},{},[1090],{"type":22,"value":1091},"post请求也可以用req.getParameter(\"key\")接收参数",{"type":17,"tag":242,"props":1093,"children":1095},{"code":1094},"@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    \u002F* 获取请求正文 *\u002F\n    ServletInputStream inputStream = req.getInputStream();\n    BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));\n​\n    \u002F\u002F 读取请求正文\n    String s = reader.readLine();\n    System.out.println(s);\n  \n    \u002F* 也可以用getParameter接收参数*\u002F\n    String firstname = req.getParameter(\"firstname\");\n    String lastname = req.getParameter(\"lastname\");\n​\n    System.out.println(firstname);\n    System.out.println(lastname);\n}\n",[1096],{"type":17,"tag":101,"props":1097,"children":1098},{"__ignoreMap":7},[1099],{"type":22,"value":1094},{"type":17,"tag":557,"props":1101,"children":1103},{"id":1102},"request对象处理中文乱码问题",[1104],{"type":22,"value":1102},{"type":17,"tag":286,"props":1106,"children":1107},{},[1108],{"type":17,"tag":18,"props":1109,"children":1110},{},[1111],{"type":22,"value":1112},"客户端向服务器的Serlvet类提交数据中包含中文，可能会出现中文乱码",{"type":17,"tag":18,"props":1114,"children":1115},{},[1116],{"type":17,"tag":97,"props":1117,"children":1118},{},[1119],{"type":22,"value":1120},"1. 为什么会出现乱码",{"type":17,"tag":18,"props":1122,"children":1123},{},[1124],{"type":17,"tag":60,"props":1125,"children":1127},{"alt":62,"src":1126},"https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fcd065e1db89149808a515cae41024ebc~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":18,"props":1129,"children":1130},{},[1131],{"type":22,"value":1132},"客户端提交的数据通过网络发送给服务器，传输的过程数据通常会进行编码，服务器会对数据进行解码；如果服务器使用的解码方法与网页的编码方式不同，将会导致服务器的解码出现乱码",{"type":17,"tag":18,"props":1134,"children":1135},{},[1136],{"type":17,"tag":97,"props":1137,"children":1138},{},[1139],{"type":22,"value":1140},"2. get方式提交数据的乱码问题",{"type":17,"tag":242,"props":1142,"children":1144},{"code":1143},"\u003CConnector port=\"8080\" protocol=\"HTTP\u002F1.1\"\n           connectionTimeout=\"20000\"\n           redirectPort=\"8443\"\n     URIEncoding=\"utf-8\" \u002F>\n",[1145],{"type":17,"tag":101,"props":1146,"children":1147},{"__ignoreMap":7},[1148],{"type":22,"value":1143},{"type":17,"tag":18,"props":1150,"children":1151},{},[1152],{"type":17,"tag":97,"props":1153,"children":1154},{},[1155],{"type":22,"value":1156},"3. post方式提交数据的乱码问题",{"type":17,"tag":242,"props":1158,"children":1160},{"code":1159},"@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    \u002F* 处理中文乱码问题*\u002F\n    req.setCharacterEncoding(\"utf-8\");\n​\n    \u002F* 也可以用getParameter接收参数 *\u002F\n    String firstname = req.getParameter(\"firstname\");\n    String lastname = req.getParameter(\"lastname\");\n​\n    System.out.println(firstname);\n    System.out.println(lastname);\n}\n",[1161],{"type":17,"tag":101,"props":1162,"children":1163},{"__ignoreMap":7},[1164],{"type":22,"value":1159},{"type":17,"tag":82,"props":1166,"children":1168},{"id":1167},"response对象",[1169],{"type":22,"value":1170},"Response对象",{"type":17,"tag":286,"props":1172,"children":1173},{},[1174],{"type":17,"tag":18,"props":1175,"children":1176},{},[1177],{"type":22,"value":1178},"Servlet类中doGet\u002FdoPost等方法都有一个HttpServletResponse对象，用于响应客户端请求",{"type":17,"tag":18,"props":1180,"children":1181},{},[1182],{"type":17,"tag":97,"props":1183,"children":1184},{},[1185],{"type":22,"value":1186},"常用方法：",{"type":17,"tag":242,"props":1188,"children":1190},{"code":1189},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n    \u002F* 设置状态行*\u002F\n    resp.setStatus(200);\n​\n    \u002F* 设置响应头 *\u002F\n    \u002F\u002F 设置响应客户端的数据格式\n    resp.setContentType(\"text\u002Fhtml\");\n    \u002F\u002F 设置响应客户端的数据长度(一般无需设置)\n    \u002F\u002F resp.setContentLength(1024);\n    \u002F\u002F 设置其他响应头属性\n    resp.setHeader(\"connection\", \"keep-alive\");\n​\n    \u002F* 设置响应正文 *\u002F\n    \u002F\u002F 设置响应客户端的数据编码格式\n    resp.setCharacterEncoding(\"utf-8\");\n    \u002F\u002F 通过response对象获取输出流\n    \u002F\u002F 字节流（如果要响应文件数据给客户端，则需要使用字节流）\n    \u002F\u002F ServletOutputStream outputStream = resp.getOutputStream();\n    \u002F\u002F 字符流（如果响应文本数据-HTML文档，则使用字符流）\n    PrintWriter writer = resp.getWriter();\n    \u002F\u002F 通过流学出的数据，就会以响应正文的形式传输给客户端浏览器，如果浏览器可以识别数据，则直接显示\n    writer.println(\"我是响应内容\");\n    writer.flush();\n    writer.close();\n}\n",[1191],{"type":17,"tag":101,"props":1192,"children":1193},{"__ignoreMap":7},[1194],{"type":22,"value":1189},{"type":17,"tag":82,"props":1196,"children":1198},{"id":1197},"cookie的使用",[1199],{"type":22,"value":1200},"Cookie的使用",{"type":17,"tag":89,"props":1202,"children":1203},{},[1204,1209,1214,1219],{"type":17,"tag":93,"props":1205,"children":1206},{},[1207],{"type":22,"value":1208},"Cookie是在浏览器在访问web服务器上的某个资源时，由web服务器在响应浏览器时通过响应头附带给浏览器并且存储在浏览端的一小段数据",{"type":17,"tag":93,"props":1210,"children":1211},{},[1212],{"type":22,"value":1213},"一旦浏览器保存来自某个服务器的Cookie，浏览器再次访问该服务器，会通过请求头将Cookie传递给web服务器",{"type":17,"tag":93,"props":1215,"children":1216},{},[1217],{"type":22,"value":1218},"浏览器访问服务器的时候，只会携带当前服务器存储在浏览器的Cookie",{"type":17,"tag":93,"props":1220,"children":1221},{},[1222],{"type":22,"value":1223},"Cookie中缓存的数据是以键值对存储的（key-value）",{"type":17,"tag":557,"props":1225,"children":1227},{"id":1226},"将cookie写给浏览器",[1228],{"type":22,"value":1229},"将Cookie写给浏览器",{"type":17,"tag":286,"props":1231,"children":1232},{},[1233],{"type":17,"tag":18,"props":1234,"children":1235},{},[1236],{"type":22,"value":1237},"服务器可以向浏览器存储多个Cookie",{"type":17,"tag":242,"props":1239,"children":1241},{"code":1240},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n​\n    \u002F* 创建Cookie *\u002F\n    Cookie cookie = new Cookie(\"key1\", \"value1\");\n​\n    \u002F* 设置生命周期 *\u002F\n    \u002F\u002F 1. 设置>0，表示Cookie有效时间，单位s\n    \u002F\u002F 2. 设置=0，表示浏览器关闭销毁Cookie\n    \u002F\u002F 3. 设置-1，表示内存存储\n    cookie.setMaxAge(24 * 60 * 60);\n​\n    \u002F* 将Cookie响应给客户端 *\u002F\n    resp.addCookie(cookie);\n​\n    \u002F* 设置响应信息 *\u002F\n    resp.setContentType(\"text\u002Fhtml\");\n    resp.setHeader(\"connection\", \"keep-alive\");\n​\n    resp.setCharacterEncoding(\"utf-8\");\n    PrintWriter writer = resp.getWriter();\n    \u002F\u002F 通过流学出的数据，就会以响应正文的形式传输给客户端浏览器，如果浏览器可以识别数据，则直接显示\n    writer.println(\"我是响应内容\");\n    writer.flush();\n    writer.close();\n}\n",[1242],{"type":17,"tag":101,"props":1243,"children":1244},{"__ignoreMap":7},[1245],{"type":22,"value":1240},{"type":17,"tag":557,"props":1247,"children":1249},{"id":1248},"从浏览器请求中读取cookie",[1250],{"type":22,"value":1251},"从浏览器请求中读取Cookie",{"type":17,"tag":242,"props":1253,"children":1255},{"code":1254},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n​\n    Cookie[] cookies = req.getCookies();\n    for (Cookie cookie : cookies) {\n        if (Objects.equals(cookie.getName(), \"key1\")) {\n            System.out.println(\"存储的Cookie为\" + cookie.getValue());\n        }\n​\n    }\n}\n",[1256],{"type":17,"tag":101,"props":1257,"children":1258},{"__ignoreMap":7},[1259],{"type":22,"value":1254},{"type":17,"tag":557,"props":1261,"children":1263},{"id":1262},"cookie的优点与限制",[1264],{"type":22,"value":1265},"Cookie的优点与限制",{"type":17,"tag":18,"props":1267,"children":1268},{},[1269],{"type":17,"tag":97,"props":1270,"children":1271},{},[1272],{"type":22,"value":1273},"优点：",{"type":17,"tag":89,"props":1275,"children":1276},{},[1277,1282,1287],{"type":17,"tag":93,"props":1278,"children":1279},{},[1280],{"type":22,"value":1281},"可以配置过期时间",{"type":17,"tag":93,"props":1283,"children":1284},{},[1285],{"type":22,"value":1286},"简洁，cookie中存储的是最简单的键值对格式的文本数据",{"type":17,"tag":93,"props":1288,"children":1289},{},[1290],{"type":22,"value":1291},"数据的持久性，保存到浏览器中的cookie在过期之前是持久存储的",{"type":17,"tag":18,"props":1293,"children":1294},{},[1295],{"type":17,"tag":97,"props":1296,"children":1297},{},[1298],{"type":22,"value":1299},"缺点：",{"type":17,"tag":89,"props":1301,"children":1302},{},[1303,1308,1313],{"type":17,"tag":93,"props":1304,"children":1305},{},[1306],{"type":22,"value":1307},"存储数据的大小，大多数浏览器支持4K、8K的数据存储",{"type":17,"tag":93,"props":1309,"children":1310},{},[1311],{"type":22,"value":1312},"用户可以通过浏览器设置禁用Cookie，限制Cookie的使用场景",{"type":17,"tag":93,"props":1314,"children":1315},{},[1316],{"type":22,"value":1317},"Cookie存储在客户端浏览器中，有被篡改的风险，有潜在的安全隐患",{"type":17,"tag":82,"props":1319,"children":1321},{"id":1320},"session对象",[1322],{"type":22,"value":1323},"Session对象",{"type":17,"tag":557,"props":1325,"children":1327},{"id":1326},"session概述",[1328],{"type":22,"value":1329},"Session概述",{"type":17,"tag":286,"props":1331,"children":1332},{},[1333],{"type":17,"tag":18,"props":1334,"children":1335},{},[1336],{"type":22,"value":1337},"Session对象，就是当浏览器向服务器发送请求建立连接后，由服务器穿件的存储在服务器用于记录用户状态的对象",{"type":17,"tag":89,"props":1339,"children":1340},{},[1341,1346],{"type":17,"tag":93,"props":1342,"children":1343},{},[1344],{"type":22,"value":1345},"服务器会为每个客户端连接分配一个Session对象，存储在服务器上",{"type":17,"tag":93,"props":1347,"children":1348},{},[1349],{"type":22,"value":1350},"同一个浏览器发送多次请求，同属于一次回话，共享同一个Session对象",{"type":17,"tag":557,"props":1352,"children":1354},{"id":1353},"session原理",[1355],{"type":22,"value":1356},"Session原理",{"type":17,"tag":286,"props":1358,"children":1359},{},[1360],{"type":17,"tag":18,"props":1361,"children":1362},{},[1363],{"type":22,"value":1364},"HTTP是无状态，同一个浏览器可以借助Cookie实现多次请求共享一个Session",{"type":17,"tag":18,"props":1366,"children":1367},{},[1368],{"type":17,"tag":60,"props":1369,"children":1371},{"alt":62,"src":1370},"https:\u002F\u002Fp3-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F60d1ba32358b4aca8de31250d250ab19~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":18,"props":1373,"children":1374},{},[1375],{"type":17,"tag":97,"props":1376,"children":1377},{},[1378],{"type":22,"value":1356},{"type":17,"tag":199,"props":1380,"children":1381},{"start":491},[1382,1387],{"type":17,"tag":93,"props":1383,"children":1384},{},[1385],{"type":22,"value":1386},"当客户端浏览器第一次请求服务器的时候，服务器会为客户端创建一个Session对象，同时将sessionID通过Cookie响应给客户端，并存储在客户端",{"type":17,"tag":93,"props":1388,"children":1389},{},[1390],{"type":22,"value":1391},"当客户端再次请求服务器的时候，请求头上会携带着存储着sessionID的cookie，服务器接收请求之后获取sessionID，通过这个sessionID获取第一次连接创建的Session对象",{"type":17,"tag":557,"props":1393,"children":1395},{"id":1394},"session的数据操作",[1396],{"type":22,"value":1394},{"type":17,"tag":1398,"props":1399,"children":1401},"h6",{"id":1400},"生成session",[1402],{"type":22,"value":1400},{"type":17,"tag":242,"props":1404,"children":1406},{"code":1405},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n    doPost(req, resp);\n}\n​\n@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) {\n    \u002F* 1. 获取当前用户连接 *\u002F\n    HttpSession session = req.getSession();\n    \u002F* 2. 为当前连接生成sessionId *\u002F\n    String sessionId = session.getId();\n    session.setAttribute(\"key1\", sessionId);\n    System.out.println(\"sessionId\" + sessionId);\n}\n",[1407],{"type":17,"tag":101,"props":1408,"children":1409},{"__ignoreMap":7},[1410],{"type":22,"value":1405},{"type":17,"tag":1398,"props":1412,"children":1414},{"id":1413},"获取session",[1415],{"type":22,"value":1413},{"type":17,"tag":242,"props":1417,"children":1419},{"code":1418},"@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n    \u002F* 获取连接 *\u002F\n    HttpSession session = req.getSession();\n​\n    \u002F* 取数据 *\u002F\n    String s1 = (String) session.getAttribute(\"key1\");\n    System.out.println(\"SecondSessionServlet===  \" + s1);\n}\n",[1420],{"type":17,"tag":101,"props":1421,"children":1422},{"__ignoreMap":7},[1423],{"type":22,"value":1418},{"type":17,"tag":1398,"props":1425,"children":1427},{"id":1426},"修改session",[1428],{"type":22,"value":1426},{"type":17,"tag":242,"props":1430,"children":1432},{"code":1431},"@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n    \u002F* 获取连接 *\u002F\n    HttpSession session = req.getSession();\n​\n    \u002F* 修改数据 *\u002F\n    session.setAttribute(\"key1\", \"修改后的session\");\n}\n",[1433],{"type":17,"tag":101,"props":1434,"children":1435},{"__ignoreMap":7},[1436],{"type":22,"value":1431},{"type":17,"tag":1398,"props":1438,"children":1440},{"id":1439},"删除session",[1441],{"type":22,"value":1439},{"type":17,"tag":242,"props":1443,"children":1445},{"code":1444},"@Override\nprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n    \u002F* 获取连接 *\u002F\n    HttpSession session = req.getSession();\n​\n    \u002F* 删除数据 *\u002F\n    session.removeAttribute(\"key1\");\n}\n",[1446],{"type":17,"tag":101,"props":1447,"children":1448},{"__ignoreMap":7},[1449],{"type":22,"value":1444},{"type":17,"tag":557,"props":1451,"children":1453},{"id":1452},"session对象失效",[1454],{"type":22,"value":1452},{"type":17,"tag":286,"props":1456,"children":1457},{},[1458,1463],{"type":17,"tag":18,"props":1459,"children":1460},{},[1461],{"type":22,"value":1462},"一个客户端的多次请求正常情况下获取到的是同一个session对象，也正是因为多次请求获取的同一个session对象才实现了session中存储的用户状态可以作用于请求",{"type":17,"tag":18,"props":1464,"children":1465},{},[1466],{"type":22,"value":1467},"如果session失效，将会导致session失效后的请求无法获取之前的session对象，也就是说多次请求获取的不是同一个session",{"type":17,"tag":18,"props":1469,"children":1470},{},[1471],{"type":17,"tag":97,"props":1472,"children":1473},{},[1474],{"type":22,"value":1475},"导致session失效的原因有两种：",{"type":17,"tag":89,"props":1477,"children":1478},{},[1479,1484],{"type":17,"tag":93,"props":1480,"children":1481},{},[1482],{"type":22,"value":1483},"客户端禁用Cookie，或者客户端在两次请求之间清楚了cookie，将导致下一次请求无法获取上一次请求的创建的session对象",{"type":17,"tag":93,"props":1485,"children":1486},{},[1487],{"type":22,"value":1488},"session是有生命周期的，当客户端请求服务器会为此创建session对象，如果客户端两次请求的间隔时间 > session过期时间（默认30min），服务器会将之前创建的session对象销毁",{"type":17,"tag":82,"props":1490,"children":1492},{"id":1491},"servletcontext对象",[1493],{"type":22,"value":1494},"ServletContext对象",{"type":17,"tag":286,"props":1496,"children":1497},{},[1498],{"type":17,"tag":18,"props":1499,"children":1500},{},[1501],{"type":22,"value":1502},"也叫application对象。是JavaWeb项目的全局对象，包含当前web项目在web服务器中的信息，同事他也是一个域对象，可以实现访问当前web项目的所有用户之间的数据共享",{"type":17,"tag":89,"props":1504,"children":1505},{},[1506],{"type":17,"tag":93,"props":1507,"children":1508},{},[1509],{"type":22,"value":1510},"Request对象作用于一个用户请求，获取用户数据",{"type":17,"tag":89,"props":1512,"children":1513},{},[1514],{"type":17,"tag":93,"props":1515,"children":1516},{},[1517],{"type":22,"value":1518},"session对象作用于一个用户的多个请求，实现数据共享",{"type":17,"tag":89,"props":1520,"children":1521},{},[1522],{"type":17,"tag":93,"props":1523,"children":1524},{},[1525],{"type":22,"value":1526},"ServletContext对象作用于整个web项目，实现多个用户之间数据共享",{"type":17,"tag":18,"props":1528,"children":1529},{},[1530],{"type":17,"tag":60,"props":1531,"children":1533},{"alt":62,"src":1532},"https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fa5c3029cd2d84e36bf0ab24011dad897~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":557,"props":1535,"children":1537},{"id":1536},"获取wen应用信息",[1538],{"type":22,"value":1536},{"type":17,"tag":242,"props":1540,"children":1542},{"code":1541},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    ServletContext servletContext = getServletContext();\n​\n    \u002F* 1. 获取当前web应用在web服务器上的访问路径 *\u002F\n    String contextPath = servletContext.getContextPath();\n    \u002F* 2. 获取web项目在服务器上的绝对路径 *\u002F\n    String realPath = servletContext.getRealPath(\"\u002Ffiles\");\n​\n    System.out.println(realPath);\n    System.out.println(\"contextPath\" + contextPath);\n}\n",[1543],{"type":17,"tag":101,"props":1544,"children":1545},{"__ignoreMap":7},[1546],{"type":22,"value":1541},{"type":17,"tag":557,"props":1548,"children":1550},{"id":1549},"实现全局数据贡献",[1551],{"type":22,"value":1549},{"type":17,"tag":18,"props":1553,"children":1554},{},[1555],{"type":17,"tag":97,"props":1556,"children":1557},{},[1558],{"type":22,"value":1559},"存储数据",{"type":17,"tag":242,"props":1561,"children":1563},{"code":1562},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    String param = req.getParameter(\"param\");\n​\n    ServletContext servletContext = getServletContext();\n  \n    \u002F* 通过application全局对象存储数据 *\u002F\n    servletContext.setAttribute(\"aKey\", param);\n}\n",[1564],{"type":17,"tag":101,"props":1565,"children":1566},{"__ignoreMap":7},[1567],{"type":22,"value":1562},{"type":17,"tag":18,"props":1569,"children":1570},{},[1571],{"type":17,"tag":97,"props":1572,"children":1573},{},[1574],{"type":22,"value":1575},"取数据",{"type":17,"tag":286,"props":1577,"children":1578},{},[1579],{"type":17,"tag":18,"props":1580,"children":1581},{},[1582],{"type":22,"value":1583},"取数据的时候你会发现无论用什么浏览器去访问这个地址，都可以取到相同的数据！",{"type":17,"tag":242,"props":1585,"children":1587},{"code":1586},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    ServletContext servletContext = getServletContext();\n​\n    \u002F* 获取通过全局对象存储的值 *\u002F\n    String aKey = (String) servletContext.getAttribute(\"aKey\");\n    System.out.println(aKey);\n}\n",[1588],{"type":17,"tag":101,"props":1589,"children":1590},{"__ignoreMap":7},[1591],{"type":22,"value":1586},{"type":17,"tag":18,"props":1593,"children":1594},{},[1595],{"type":17,"tag":97,"props":1596,"children":1597},{},[1598],{"type":22,"value":1599},"修改数据",{"type":17,"tag":242,"props":1601,"children":1603},{"code":1602},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    ServletContext servletContext = getServletContext();\n​\n    \u002F* 修改全局对象的数据 *\u002F\n    servletContext.setAttribute(\"aKey\",\"我是修改过后的数据\");\n}\n",[1604],{"type":17,"tag":101,"props":1605,"children":1606},{"__ignoreMap":7},[1607],{"type":22,"value":1602},{"type":17,"tag":18,"props":1609,"children":1610},{},[1611],{"type":17,"tag":97,"props":1612,"children":1613},{},[1614],{"type":22,"value":1615},"删数据",{"type":17,"tag":242,"props":1617,"children":1619},{"code":1618},"@Override\nprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n​\n    ServletContext servletContext = getServletContext();\n​\n    \u002F* 删除全局对象指定的数据 *\u002F\n    servletContext.removeAttribute(\"aKey\");\n}\n",[1620],{"type":17,"tag":101,"props":1621,"children":1622},{"__ignoreMap":7},[1623],{"type":22,"value":1618},{"type":17,"tag":557,"props":1625,"children":1627},{"id":1626},"总结",[1628],{"type":22,"value":1629},"总结：",{"type":17,"tag":89,"props":1631,"children":1632},{},[1633,1638,1643],{"type":17,"tag":93,"props":1634,"children":1635},{},[1636],{"type":22,"value":1637},"ServletContext是当前web项目的全局上下文对象，可以被多个用户请求共享",{"type":17,"tag":93,"props":1639,"children":1640},{},[1641],{"type":22,"value":1642},"ServletContext是服务器启动的时候创建的，当服务器关闭或者将项目从服务器移出时销毁ServletContext对象",{"type":17,"tag":93,"props":1644,"children":1645},{},[1646],{"type":22,"value":1647},"ServletContext可以实现在线人数统计等需要全局存储的场景",{"title":7,"searchDepth":1649,"depth":1649,"links":1650},2,[1651,1657],{"id":52,"depth":1649,"text":55,"children":1652},[1653,1655,1656],{"id":68,"depth":1654,"text":68},3,{"id":195,"depth":1654,"text":195},{"id":282,"depth":1654,"text":282},{"id":383,"depth":1649,"text":386,"children":1658},[1659,1660,1661],{"id":437,"depth":1654,"text":440},{"id":786,"depth":1654,"text":789},{"id":1030,"depth":1654,"text":1033},"markdown","content:articles:backend:tomcat-servlet.md","content","articles\u002Fbackend\u002Ftomcat-servlet.md","articles\u002Fbackend\u002Ftomcat-servlet","md",1779811690140]