Client / Server(客户端 / 服务器)
C/S架构的软件或者说系统有哪些呢?
QQ(先去腾讯官网下载一个QQ软件,,然后把这个客户端软件安装上去)
C/S架构的特点:需要安装特定的客户端软件。
C/S架构的系统优点和缺点分别是什么?
优点:
速度快(软件中的数据大部分都是集成到客户端软件当中的,很少量的数据从服务器端传送过来,1所以C/S结构的系统速度快)
体验好(速度又快,界面又酷炫,当然体验好)
界面酷炫(专门的语言去实现界面的,更加灵活)
服务器压力小(因为大量的数据都是集成在客户端软件当中,所以服务器只需要传送很少的数据量,当然服务器压力小。)
安全(因为大量的数据是集成在客户端软件当中的,并且客户端有很多个,服务器虽然只有一个,就算服务器那边地震了,火灾了,服务器受损了,问题也不大,因为大量的数据在多个客户端上有缓存,有存储,所以从这个方面来说,C/S结构的系统比较安全。)
…
缺点:
升级维护比较差劲。(升级维护比较麻烦。成本比较高。每一个客户端软件都需要升级。有一些软件不是那么容易安装的。)
B/S(Browser / Server,浏览器 / 服务器)
http://www.baidu.com
http://www.jd.com
http://www.126.com
B/S结构的系统是不是一个特殊的C/S系统?
实际上B/S结构的系统还是一个C/S,只不过这个C比较特殊,这个Client是一个固定不变的浏览器软件。
B/S结构的系统优点和缺点是:
优点:
升级维护方便,成本比较低。(只需要升级服务器端即可。)
不需要安装特定的客户端软件,用户操作极其方便。只需要打开浏览器,输入网址即可。
缺点:
速度慢(不是因为带宽低的问题,是因为所有的数据都是在服务器上,用户发送的每一个请求都是需要服务器全身心的响应数据,所以B/S结构的系统在网络中传送的数据量比较大。)
体验差(界面不是那么酷炫,因为浏览器只支持三个语言HTML CSS JavaScript。在加上速度慢。)
不安全(所有的数据都在服务器上,只要服务器发生火灾,地震等不可抗力,最终数据全部丢失。)
这个问题问的没有水平。并不是哪个好,哪个不好。不同结构的系统在不同的业务场景下有不同的适用场景。
娱乐性软件建议使用?
C/S结构
公司内部使用的一些业务软件建议使用?
公司内部使用的系统,需要维护成本低。
公司内部使用的系统,不需要很酷炫。
公司内部使用的企业级系统主要是能够进行数据的维护即可。
B/S结构。
开发一个WEB系统,你需要会哪些技术?
WEB前端(运行在浏览器上的程序)
HTML、CSS、JavaScript
WEB后端(WEB服务器端的程序)
Java可以(Java做WEB开发我们称为JavaWeb开发。JavaWeb开发最核心的规范:Servlet【Server Applet 服务器端的Java小程序。】)
C语言也可以,C++也可以,Python也行,PHP也可以。
Java包括三大块:
- JavaSE
Java标准版(一套类库:别人写好的一套类库,只不过这个类库是标准类库,走EE或者走ME,这个SE一定是基础,先学。)
- JavaEE(WEB方向,WEB系统)
Java企业版(也是一套类库:也是别人写好的一套类库,只不过这套类库可以帮助我们完成企业级项目的开发,专门为企业内部提供解决方案的一套(多套)类库。)
别人写好的,你用就行了,用它可以开发企业级项目。
可以开发web系统。
- JavaME
Java微型版(还是一套类库,只不过这套类库帮助我们进行电子微型设备内核程序的开发)
机顶盒内核程序,吸尘器内核程序,电冰箱内核程序,电饭煲内核程序。
JavaEE实际上包括很多种规范,13种规范,其中Servlet就是JavaEE规范之一,学Servlet还是Java语言。
doctype html>
<html>
<head>
<title>index pagetitle>
head>
<body>
<h1>my index page!h1>
<br>
<a href="http://127.0.0.1:8080/oa/login.html">user logina>
<a href="/oa/login.html">user login2a>
<a href="/oa/test/debug/d.html">d pagea>
body>
html>
package org.apache;
import java.util.Scanner;
import java.util.Properties;
import java.io.FileReader;
import javax.servlet.Servlet;
// 充当Tomcat服务器的开发者
public class Tomcat{
public static void main(String[] args) throws Exception{
System.out.println("Tomcat服务器启动成功,开始接收用户的访问。");
// 简单的使用Scanner来模拟一下用户的请求
// 用户访问服务器是通过浏览器上的“请求路径”
// 也就是说用户请求路径不同,后台执行的Servlet不同。
System.out.print("请输入您的访问路径:");
Scanner s = new Scanner(System.in);
// 用户的请求路径
String key = s.nextLine(); // Tomcat服务器已经获取到了用户的请求路径了。
// Tomcat服务器应该通过用户的请求路径找对应的XXXServlet
// 请求路径和XXXServlet之间的关系应该由谁来指定呢?
// 对于Tomcat服务器来说,需要解析配置文件
FileReader reader = new FileReader("web.properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
// 通过key获取value
String className = pro.getProperty(key);
// 通过反射机制创建对象
Class clazz = Class.forName(className);
Object obj = clazz.newInstance(); //obj的类型对于Tomcat服务器开发人员来说不知道。
// 但是Tomcat服务器的开发者知道,你写的XXXServlet一定实现了Servlet接口
Servlet servlet = (Servlet) obj;
servlet.service();
}
}
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
web-app>
CLASSPATH=.;C:\dev\apache-tomcat-10.0.12\lib\servlet-api.jar
- 思考问题:以上配置的CLASSPATH和Tomcat服务器运行有没有关系?
- 没有任何关系,以上配置这个环境变量只是为了让你的HelloServlet能够正常编译生成class文件。
package com.bjpowernode.servlet;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletConfig;
import java.io.PrintWriter;
import java.io.IOException;
public class HelloServlet implements Servlet{
// 5个方法
public void init(ServletConfig config) throws ServletException{
}
public void service(ServletRequest request,ServletResponse response)
throws ServletException,IOException {
// 向控制台打印输出
System.out.println("My First Servlet, Hello Servlet");
// 设置响应的内容类型是普通文本或html代码
// 需要在获取流对象之前设置,有效。
response.setContentType("text/html");
// 怎么将一个信息直接输出到浏览器上?
// 需要使用ServletResponse接口:response
// response表示响应:从服务器向浏览器发送数据叫做响应。
PrintWriter out = response.getWriter();
out.print("Hello Servlet, You are my first servlet!");
// 浏览器是能够识别html代码的,那我们是不是应该输出一段HTML代码呢?
out.print("hello servlet,你好Servlet
");
// 这是一个输出流,负责输出字符串到浏览器
// 这个输出流不需要我们刷新,也不需要我们关闭,这些都由Tomcat来维护。
}
public void destroy(){
}
public String getServletInfo(){
return "";
}
public ServletConfig getServletConfig(){
return null;
}
}
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
<servlet>
<servlet-name>abcdservlet-name>
<servlet-class>com.bjpowernode.servlet.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>abcdservlet-name>
<url-pattern>/a/b/c/durl-pattern>
servlet-mapping>
web-app>
webapproot
|------WEB-INF
|------classes(存放字节码)
|------lib(第三方jar包)
|------web.xml(注册Servlet)
|------html
|------css
|------javascript
|------image
....
将CATALINA_HOME/conf/logging.properties文件中的内容修改如下:
java.util.logging.ConsoleHandler.encoding = GBK
public void service(ServletRequest request,ServletResponse response)
throws ServletException,IOException {
// 向控制台打印输出
System.out.println("My First Servlet, Hello Servlet");
// 设置响应的内容类型是普通文本或html代码
// 需要在获取流对象之前设置,有效。
response.setContentType("text/html");
// 怎么将一个信息直接输出到浏览器上?
// 需要使用ServletResponse接口:response
// response表示响应:从服务器向浏览器发送数据叫做响应。
PrintWriter out = response.getWriter();
out.print("Hello Servlet, You are my first servlet!");
// 浏览器是能够识别html代码的,那我们是不是应该输出一段HTML代码呢?
out.print("hello servlet,你好Servlet
");
// 这是一个输出流,负责输出字符串到浏览器
// 这个输出流不需要我们刷新,也不需要我们关闭,这些都由Tomcat来维护。
}
public void service(ServletRequest request,ServletResponse response)
throws ServletException,IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
// 注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 获取连接
String url = "jdbc:mysql://localhost:3306/bjpowernode?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=UTF-8&useUnicode=true";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url,user,password);
// 获取预编译的数据库操作对象
String sql = "select * from t_student";
ps = conn.prepareStatement(sql);
// 执行SQL
rs = ps.executeQuery();
// 处理查询结果集
while(rs.next()){
String no = rs.getString("no");
String name = rs.getString("name");
out.print(no + "," + name + "
");
}
}catch(Exception e){
e.printStackTrace();
}finally{
// 释放资源
if(rs != null){
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(ps != null){
try{
ps.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>studentServletservlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.StudentServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>studentServletservlet-name>
<url-pattern>/servlet/studenturl-pattern>
servlet-mapping>
web-app>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>student pagetitle>
head>
<body>
<a href="/xmm/servlet/student">student lista>
body>
html>
子标签,在该子标签中填写整数,越小的整数优先级越高。<servlet>
<servlet-name>aservletservlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.AServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>aservletservlet-name>
<url-pattern>/aurl-pattern>
servlet-mapping>
AServlet无参数构造方法执行了
AServlet's init method execute!
AServlet's service method execute!
AServlet's service method execute!
AServlet's destroy method execute!
public class Tomcat{
public static void main(String[] args){
// .....
// Tomcat服务器伪代码
// 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
Class clazz = Class.forName("com.bjpowernode.javaweb.servlet.LoginServlet");
Object obj = clazz.newInstance();
// 向下转型
Servlet servlet = (Servlet)obj;
//创建ServletConfig对象
// Tomcat服务器负责将ServletConfig对象实例化出来。
// 多态(Tomcat服务器完全实现了Servlet规范)
ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();
// 调用Servlet的init方法
servlet.init(servletConfig);
//调用servlet的service方法
// ....
}
}
<servlet>
<servlet-name>configTestservlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.ConfigTestServletservlet-class>
<init-param>
<param-name>driverparam-name>
<param-value>com.mysql.cj.jdbc.Driverparam-value>
init-param>
<init-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306/bjpowernodeparam-value>
init-param>
<init-param>
<param-name>userparam-name>
<param-value>rootparam-value>
init-param>
<init-param>
<param-name>passwordparam-name>
<param-value>123456param-value>
init-param>
servlet>
通过ServletConfig对象的两个方法,可以获取到web.xml文件中的初始化参数配置信息。
java.util.Enumeration<java.lang.String> getInitParameterNames() 获取所有的初始化参数的name
java.lang.String getInitParameter(java.lang.String name) 通过初始化参数的name获取value
// 获取ServletConfig对象
ServletConfig config = this.getServletConfig();
Enumeration<String> parameterNames = config.getInitParameterNames();
// 遍历集合
while(parameterNames.hasMoreElements()){ // 是否有更多元素
String parameterName = parameterNames.nextElement(); // 取元素
String parameterVal = config.getInitParameter(parameterName); // 通过name获取value
out.print(parameterName + "=" + parameterVal);
out.print("
");
}
=====================================================================================
// 实际上获取一个Servlet对象的初始化参数,可以不用获取ServletConfig对象。直接通过this也可以。
Enumeration<String> names = this.getInitParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = this.getInitParameter(name);
// 打印到后台
System.out.println(name + "=" + value);
}
public String getInitParameter(String name); // 通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name
public ServletContext getServletContext(); // 获取ServletContext对象
public String getServletName(); // 获取Servlet的name
On ‘Update’ action 表示点击update按钮时会怎么做。Show dialog选上表示会打开对话框给我们选择确认。
On frame deactivation 表示焦点离开IDEA会怎么做。
public String getInitParameter(String name); // 通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames(); // 获取所有的初始化参数的name
<context-param>
<param-name>pageSizeparam-name>
<param-value>10param-value>
context-param>
<context-param>
<param-name>startIndexparam-name>
<param-value>0param-value>
context-param>
// 获取应用的根路径(非常重要),因为在java源代码当中有一些地方可能会需要应用的根路径,这个方法可以动态获取应用的根路径
// 在java源码当中,不要将应用的根路径写死,因为你永远都不知道这个应用在最终部署的时候,起一个什么名字
public String getContextPath();
// String contextPath = application.getContextPath();
// 获取文件的绝对路径(真实路径)
public String getRealPath(String path);
例:
// 后面的这个路径,加了一个“/”,这个“/”代表的是web的根
// String realPath = application.getRealPath("/index.html");
// 不加“/”,默认也是从根下开始找。
String realPath = application.getRealPath("index.html");
out.print(realPath + "
");
// 通过ServletContext对象也是可以记录日志的
public void log(String message);
public void log(String message, Throwable t);
// 这些日志信息记录到哪里了?
// localhost.2022-04-23.log
// Tomcat服务器的logs目录下都有哪些日志文件?
//catalina.2022-04-23.log 服务器端的java程序运行的控制台信息。
//localhost.2022-04-23.log ServletContext对象的log方法记录的日志信息存储到这个文件中。
//localhost_access_log.2022-04-23.txt 访问日志。
// ServletContext对象还有另一个名字:应用域(后面还有其他域,例如:请求域、会话域)
// 如果所有的用户共享一份数据,并且这个数据很少的被修改,并且这个数据量很少,可以将这些数据放到ServletContext这个应用域中
// 为什么是所有用户共享的数据? 不是共享的没有意义。因为ServletContext这个对象只有一个。只有共享的数据放进去才有意义。
// 为什么数据量要小? 因为数据量比较大的话,太占用堆内存,并且这个对象的生命周期比较长,服务器关闭的时候,这个对象才会被销毁。大数据量会影响服务器的性能。占用内存较小的数据量可以考虑放进去。
// 为什么这些共享数据很少的修改,或者说几乎不修改? 所有用户共享的数据,如果涉及到修改操作,必然会存在线程并发所带来的安全问题。所以放在ServletContext对象中的数据一般都是只读的。
// 数据量小、所有用户共享、又不修改,这样的数据放到ServletContext这个应用域当中,会大大提升效率。因为应用域相当于一个缓存,放到缓存中的数据,下次再用的时候,不需要从数据库中再次获取,大大提升执行效率。
// 存(怎么向ServletContext应用域中存数据)
public void setAttribute(String name, Object value); // map.put(k, v)
// 取(怎么从ServletContext应用域中取数据)
public Object getAttribute(String name); // Object v = map.get(k)
// 删(怎么删除ServletContext应用域中的数据)
public void removeAttribute(String name); // map.remove(k)
jakarta.servlet.Servlet(接口)【爷爷】
jakarta.servlet.GenericServlet implements Servlet(抽象类)【儿子】
jakarta.servlet.http.HttpServlet extends GenericServlet(抽象类)【孙子】
我们以后编写的Servlet要继承HttpServlet类。
GET /servlet05/getServlet?username=lucy&userpwd=1111 HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
请求体
POST /servlet05/postServlet HTTP/1.1 请求行
Host: localhost:8080 请求头
Connection: keep-alive
Content-Length: 25
Cache-Control: max-age=0
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://localhost:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
空白行
username=lisi&userpwd=123 请求体
HTTP/1.1 200 ok 状态行
Content-Type: text/html;charset=UTF-8 响应头
Content-Length: 160
Date: Mon, 25 Apr 2022 02:38:01 GMT
Keep-Alive: timeout=20
Connection: keep-alive
空白行
响应体
from get servlet
from get servlet
package com.bjpowernode.template1;
/**
* Teacher和Student都是Person
* 1.Person就是模板方法设计模式当中的模板类。
* 2.day()方法就是模板方法设计模式当中的模板方法。
*/
public abstract class Person { // 模板类通常是抽象类。
// 模板方法
// 添加了final之后,这个方法无法被覆盖,这样核心的算法也可以得到保护。
// 模板方法定义核心的算法骨架,具体的实现步骤可以延迟到子类当中去实现。
// 核心算法一方面是得到了保护,不能被改变。另外一方面就是算法得到了重复使用。
// 另外代码也得到了复用,因为算法中某些步骤的代码是固定的。这些固定的代码不会随着子类的变化而变化,这一部分代码可以写到模板类当中。
public final void day(){
qiChuang();
xiShu();
chiZaoCan();
doSome();
chiWanFan();
shuiJiao();
}
// 其中的某些步骤,不会随着子类的变化而变化,这些代码可以写到父类中,得到代码复用。
public void qiChuang(){
System.out.println("起床");
}
public void xiShu(){
System.out.println("洗漱");
}
public void chiZaoCan(){
System.out.println("吃早餐");
}
// 这一步是要做,但是具体这一步怎么做,子类说了算。
public abstract void doSome();
public void chiWanFan(){
System.out.println("吃晚饭");
}
public void shuiJiao(){
System.out.println("睡觉");
}
}
public class HelloServlet extends HttpServlet {
// 用户第一次请求,创建HelloServlet对象的时候,会执行这个无参数构造方法。
public HelloServlet() {
}
//override 重写 doGet方法
//override 重写 doPost方法
}
public abstract class GenericServlet implements Servlet, ServletConfig,
java.io.Serializable {
// 用户第一次请求的时候,HelloServlet对象第一次被创建之后,这个init方法会执行。
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
// 用户第一次请求的时候,带有参数的init(ServletConfig config)执行之后,会执行这个没有参数的init()
public void init() throws ServletException {
// NOOP by default
}
}
// HttpServlet模板类。
public abstract class HttpServlet extends GenericServlet {
// 用户发送第一次请求的时候这个service会执行
// 用户发送第N次请求的时候,这个service方法还是会执行。
// 用户只要发送一次请求,这个service方法就会执行一次。
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
// 将ServletRequest和ServletResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException(lStrings.getString("http.non_http")); //"Non HTTP request or response"
}
// 调用重载的service方法。
service(request, response);
}
// 这个service方法的两个参数都是带有Http的。
// 这个service是一个模板方法。
在该方法中定义核心算法骨架,具体的实现步骤延迟到子类中去完成。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取请求方式
// 这个请求方式最终可能是:
// 注意:request.getMethod()方法获取的是请求方式,可能是七种之一:
// GET POST PUT DELETE HEAD OPTIONS TRACE
String method = req.getMethod();
// 如果请求方式是GET请求,则执行doGet方法。
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
// 如果请求方式是POST请求,则执行doPost方法。
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 报405错误
String msg = lStrings.getString("http.method_get_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 报405错误
String msg = lStrings.getString("http.method_post_not_supported");
sendMethodNotAllowed(req, resp, msg);
}
}
/*
通过以上源代码分析:
假设前端发送的请求是get请求,后端程序员重写的方法是doPost
假设前端发送的请求是post请求,后端程序员重写的方法是doGet
会发生什么呢?
发生405这样的一个错误。
405表示前端的错误,发送的请求方式不对。和服务器不一致。不是服务器需要的请求方式。
通过以上源代码可以知道:只要HttpServlet类中的doGet方法或doPost方法执行了,必然405.
怎么避免405的错误呢?
后端重写了doGet方法,前端一定要发get请求。
后端重写了doPost方法,前端一定要发post请求。
这样可以避免405错误。
这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。
有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。
这样,确实可以避免405的发生,但是不建议,405错误还是有用的。该报错的时候就应该让它报错。
如果你要是同时重写了doGet和doPost,那还不如你直接重写service方法好了。这样代码还能少写一点。
*/
<welcome-file-list>
<welcome-file>login.htmlwelcome-file>
welcome-file-list>
- 注意:**设置欢迎页面的时候,这个路径不需要以“/”开始。并且这个路径默认是从webapp的根下开始查找**。
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2699848/1650952351261-ea342bf8-b695-485d-84cf-3a2c7495ee6f.png)
<welcome-file-list>
<welcome-file>page1/page2/page.htmlwelcome-file>
welcome-file-list>
- 注意:**路径不需要以“/”开始,并且路径默认从webapp的根下开始找**。
<welcome-file-list>
<welcome-file>page1/page2/page.htmlwelcome-file>
<welcome-file>login.htmlwelcome-file>
welcome-file-list>
<welcome-file-list>
<welcome-file>index.htmlwelcome-file>
<welcome-file>index.htmwelcome-file>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
- Tomcat服务器的全局欢迎页面是:index.html index.htm index.jsp。如果你一个web站点没有设置局部的欢迎页面,Tomcat服务器就会以index.html index.htm index.jsp作为一个web站点的欢迎页面。
- 注意原则:局部优先原则。(就近原则)
public class WelcomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.print("welcome to servlet
");
}
}
- 第二步:在web.xml文件中配置servlet
<servlet>
<servlet-name>welcomeServletservlet-name>
<servlet-class>com.bjpowernode.javaweb.servlet.WelcomeServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>welcomeServletservlet-name>
<url-pattern>/adasf/afaf/fsdf/dfsurl-pattern>
servlet-mapping>
- 第三步:在web.xml文件中配置欢迎页
<welcome-file-list>
<welcome-file>adasf/afaf/fsdf/dfswelcome-file>
welcome-file-list>
public interface HttpServletRequest extends ServletRequest {}
public class RequestFacade implements HttpServletRequest {}
Map<String,String[]> getParameterMap() 这个是获取Map
Enumeration<String> getParameterNames() 这个是获取Map集合中所有的key
String[] getParameterValues(String name) 根据key获取Map集合的value
String getParameter(String name) 获取value这个一维数组当中的第一个元素,这个方法最常用。
// 以上4个方法,和获取用户提交的数据有关系。
Map<String,String>
key存储String
value存储String
这种想法对吗?不对。
如果采用以上的数据结构存储会发现key重复的时候value覆盖。
key value
---------------------
username abc
userpwd 111
aihao s
aihao d
aihao tt
这样是不行的,因为map的key不能重复。
Map<String, String[]>
key存储String
value存储String[]
key value
-------------------------------
username {"abc"}
userpwd {"111"}
aihao {"s","d","tt"}
void setAttribute(String name, Object obj); // 向域当中绑定数据。
Object getAttribute(String name); // 从域当中根据name获取数据。
void removeAttribute(String name); // 将域当中绑定的数据移除
// 以上的操作类似于Map集合的操作。
Map<String, Object> map;
map.put("name", obj); // 向map集合中放key和value
Object obj = map.get("name"); // 通过map集合的key获取value
map.remove("name"); // 通过Map集合的key删除key和value这个键值对。
void serAttribute(String name, Object obj); // 向域当中绑定数据。
Object getAttribute(String name); // 从域当中根据name获取数据。
void removeAttribute(String name); // 将域当中绑定的数据移除
- 请求域和应用域的选用原则?
- **尽量使用小的域对象,因为小的域对象占用的资源较少**。
// 第一步:获取请求转发器对象
// 相当于把"/b"这个路径包装到请求转发器当中,实际上是把下一个跳转的资源的路径告知给Tomcat服务器了。
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
// 第二步:调用转发器的forward方法完成跳转/转发
dispatcher.forward(request,response);
// 第一步和第二步代码可以联合在一起。
request.getRequestDispatcher("/b").forward(request,response);
// uri?username=zhangsan&userpwd=123&sex=1
String username = request.getParameter("username");
// 之前一定是执行过:request.setAttribute("name",new Object())
Object obj = request.getAttribute("name");
// 以上两个方法的区别是什么?
// 第一个方法:获取的是用户在浏览器上提交的数据。
// 第二个方法:获取的是请求域当中绑定的数据。
// 获取客户端的IP地址
String remoteAddr = request.getRemoteAddr(); // 127.0.0.1
// 获取客户端的主机地址和端口
System.out.println(request.getRemoteHost() + ":" + request.getRemotePort()); // 127.0.0.1:54139
// get请求在请求行上提交数据。
// post请求在请求体中提交数据。
// 设置请求体的字符集。(显然这个方法是处理POST请求的乱码问题。这种方式并不能解决get请求的乱码问题。)
// Tomcat10之后,request请求体当中的字符集默认就是UTF-8,不需要设置字符集,不会出现乱码问题。
// Tomcat9前(包括9在内),如果前端请求体提交的是中文,后端获取之后出现乱码,怎么解决这个乱码?执行以下代码。
request.setCharacterEncoding("UTF-8");
// 在Tomcat9之前(包括9),响应中文也是有乱码的,怎么解决这个响应的乱码?
response.setContentType("text/html;charset=UTF-8");
// 在Tomcat10之后,包括10在内,响应中文的时候就不再出现乱码问题了。以上代码就不需要设置UTF-8了。
// 注意一个细节
// 在Tomcat10包括10在内之后的版本,中文将不再出现乱码。(这也体现了中文地位的提升。)其实是Tomcat10支持了多种语言了。
// get请求乱码问题怎么解决?
// get请求发送的时候,数据是在请求行上提交的,不是在请求体当中提交的。
// get请求乱码怎么解决
// 方案:修改CATALINA_HOME/conf/server.xml配置文件,在Connector中添加URIEncoding="UTF-8"(可以在tomcat目录下webapps/docs/config/http.html中查看Connector标签内可以配置什么属性)
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
// 注意:从Tomcat8之后,URIEncoding的默认值就是UTF-8,所以GET请求也没有乱码问题了。
// 获取应用的根路径
String contextPath = request.getContextPath(); // /servlet08
// 获取请求方式
String method = request.getMethod(); // POST
// 获取请求的URI
String uri = request.getRequestURI(); // /servlet08/testRequest
// 获取servlet path
String servletPath = request.getServletPath(); // /testRequest
# 部门表
drop table if exists dept;
create table dept(
deptno int primary key,
dname varchar(255),
loc varchar(255)
);
insert into dept(deptno, dname, loc) values(10, 'XiaoShouBu', 'BEIJING');
insert into dept(deptno, dname, loc) values(20, 'YanFaBu', 'SHANGHAI');
insert into dept(deptno, dname, loc) values(30, 'JiShuBu', 'GUANGZHOU');
insert into dept(deptno, dname, loc) values(40, 'MeiTiBu', 'SHENZHEN');
commit;
select * from dept;
- 我们应该怎么去实现一个功能呢?
- 建议:你可以从后端往前端一步一步写。也可以从前端一步一步往后端写。都可以。但是千万要记住不要想起来什么写什么。你写代码的过程最好是程序的执行过程。也就是说:程序执行到哪里,你就写哪里。这样一个顺序流下来之后,基本上不会出现什么错误和意外。
- 从哪里开始?
- 假设从前端开始,那么一定是从用户点击按钮那里开始的。
- 第一:先修改前端页面的超链接,因为用户先点击的就是这个超链接。
<a href="/oa/dept/list">查看部门列表a>
- 第二:编写web.xml文件
<servlet>
<servlet-name>listservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptListServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>listservlet-name>
<url-pattern>/dept/listurl-pattern>
servlet-mapping>
- 第三:编写DeptListServlet类继承HttpServlet类。然后重写doGet方法。
package com.bjpowernode.oa.web.action;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
- 第四:在DeptListServlet类的doGet方法中连接数据库,查询所有的部门,动态的展示部门列表页面。
- 分析list.html页面中哪部分是固定死的,哪部分是需要动态展示的。
- list.html页面中的内容所有的双引号要替换成单引号,因为out.print("")这里有一个双引号,容易冲突。
- 现在写完这个功能之后,你会有一种感觉,感觉开发很繁琐,只使用servlet写代码太繁琐了。
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DeptListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("");
out.print("");
out.print(" ");
out.print(" ");
out.print(" 部门列表页面 ");
out.print(" ");
out.print(" ");
out.print(" 部门列表
");
out.print("
");
out.print(" ");
out.print(" ");
out.print(" 序号 ");
out.print(" 部门编号 ");
out.print(" 部门名称 ");
out.print(" 操作 ");
out.print(" ");
/*上面一部分是死的*/
// 连接数据库,查询所有的部门
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 获取连接
conn = DBUtil.getConnection();
// 获取预编译的数据库操作对象
String sql = "select deptno as a,dname,loc from dept";
ps = conn.prepareStatement(sql);
// 执行SQL
rs = ps.executeQuery();
// 处理结果集
int i = 0;
while (rs.next()){
String deptno = rs.getString("a");
String dname = rs.getString("dname");
String loc = rs.getString("loc");
out.print(" ");
out.print(" "+(++i)+" ");
out.print(" "+deptno+" ");
out.print(" "+dname+" ");
out.print(" ");
out.print(" 删除");
out.print(" 修改");
out.print(" 详情");
out.print(" ");
out.print(" ");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 释放资源
DBUtil.close(conn,ps,rs);
}
/*下面一部分是死的*/
out.print("
");
out.print("
");
out.print(" 新增部门");
out.print(" ");
out.print("");
}
}
- 建议:从前端往后端一步一步实现。首先要考虑的是,用户点击的是什么?用户点击的东西在哪里?
- 一定要先找到用户点的“详情”在哪里。找了半天,终于在后端的java程序中找到了
<a href='写一个路径'>详情a>
- 详情 是需要连接数据库的,所以这个超链接点击之后也是需要执行一段java代码的。所以要将这个超链接的路径修改一下。
- 注意:修改路径之后,这个路径是需要加项目名的。"/oa/dept/detail"
- 技巧:
out.print("详情");
- 重点:向服务器提交数据的格式:uri?name=value&name=value&name=value
- 这里的问号,必须是英文的问号。不能中文的问号。
- 解决404的问题。写web.xml文件。
<servlet>
<servlet-name>detailservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptDetailServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>detailservlet-name>
<url-pattern>/dept/detailurl-pattern>
servlet-mapping>
- 编写一个类:DeptDetailServlet类继承HttpServlet类,重写doGet方法。
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DeptDetailServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 中文思路(思路来源于:你要做什么?目标:查看部门详细信息。)
// 第一步:获取部门编号
// 第二步:根据部门编号查询数据库,获取该部门编号对应的部门信息。
// 第三步:将部门信息响应到浏览器上。
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("");
out.println("");
out.println(" ");
out.println(" ");
out.println(" 部门详情 ");
out.println(" ");
out.println(" ");
out.println(" 部门详情
");
out.println("
");
// 获取部门编号
// /oa/dept/detail?deptno=30
// 虽然是提交的30,但是服务器获取的是“30”这个字符串。
String deptno = request.getParameter("deptno");
// 连接数据库,根据部门编号查询部门信息。
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select dname,loc from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
rs = ps.executeQuery();
// 这个结果集一定只有一条记录。
if (rs.next()) {
String dname = rs.getString("dname");
String loc = rs.getString("loc");
out.println("部门编号:"+deptno+"
");
out.println("部门名称:"+dname+"
");
out.println("部门位置:"+loc+"
");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
out.println(" ");
out.println(" ");
out.println("");
}
}
- 怎么开始?从哪里开始?从前端页面开始,用户点击删除按钮的时候,应该提示用户是否删除。因为删除这个动作是比较危险的。任何系统在进行删除操作之前,是必须要提示用户的,因为这个删除的动作有可能是用户误操作。(在前端页面上写JS代码,来提示用户是否删除。)
<a href="javascript:void(0)" onclick="del(20)">删除a>
<script type="text/javascript">
function del(dno){
// 弹出确认框,用户点击确定返回true,点击取消返回false
if(window.confirm("亲,删了不可恢复哦!")){
// 发送请求进行删除数据的操作。
// 在JS代码当中如何发送请求给服务器?
document.location.href = "/oa/dept/delete?deptno=" + dno;
//document.location = "请求路径"
//window.location.href = "请求路径"
//window.location = "请求路径"
}
}
script>
- 以上的前端程序要写到后端的java代码当中:
- DeptListServlet类的doGet方法当中,使用out.print()方法,将以上的前端代码输出到浏览器上。
- 解决404的问题:
- http://localhost:8080/oa/dept/delete?deptno=10
- web.xml文件
<servlet>
<servlet-name>deleteservlet-name>
<servlet-class>com.bjpowernode.oa.web.action.DeptDelServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>deleteservlet-name>
<url-pattern>/dept/deleteurl-pattern>
servlet-mapping>
- 编写DeptDelServlet类继承HttpServlet类,重写doGet方法。
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DeptDelServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 根据部门编号,删除部门
// 获取部门编号
String deptno = request.getParameter("deptno");
// 连接数据库删除数据
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getConnection();
// 开启事务
conn.setAutoCommit(false);
String sql = "delete from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1,deptno);
// 返回值是:影响了数据库表当中多少条记录
count = ps.executeUpdate();
// 事务提交
conn.commit();
} catch (SQLException throwables) {
throwables.printStackTrace();
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
} finally {
DBUtil.close(conn,ps,null);
}
// 判断删除成功了还是失败了
if (count == 1){
// 删除成功
// 仍然跳转到部门列表页面
// 部门列表页面的显示需要执行另一个Servlet。怎么办?转发。
request.getRequestDispatcher("/dept/list").forward(request,response);
} else {
request.getRequestDispatcher("/error.html").forward(request,response);
}
}
}
- 删除成功或者失败的时候的一个处理(这里我们选择了转发,并没有使用重定向机制。)
- 注意:最后保存成功之后,转发到 /dept/list 的时候,会出现405,为什么?
- 第一:保存用的是post请求。底层要执行doPost方法。
- 第二:转发是一次请求,之前是post,之后还是post,因为它是一次请求。
- 第三: /dept/list Servlet当中只有一个doGet方法。
- 怎么解决?两种方案
- 第一种:在/dept/list Servlet中添加doPost方法,然后在doPost方法中调用doGet。
- 第二种:重定向。
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DeptSaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取部门的信息
// 注意乱码问题(Tomcat10不会出现这个问题)
request.setCharacterEncoding("UTF-8");
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 连接数据库执行insert语句
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getConnection();
String sql = "insert into dept(deptno,dname,loc) values(?,?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
ps.setString(2, dname);
ps.setString(3, loc);
count = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
if (count == 1){
// 保存成功跳转到列表页面
// 转发是一次请求。
request.getRequestDispatcher("/dept/list").forward(request,response);
} else {
// 保存失败跳转到错误页面
request.getRequestDispatcher("/error.html").forward(request,response);
}
}
}
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DeptEditServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取应用的根路径。
String contextPath = request.getContextPath();
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("");
out.print("");
out.print(" ");
out.print(" ");
out.print(" 修改部门 ");
out.print(" ");
out.print(" ");
out.print(" 修改部门
");
out.print("
");
out.print(" );
// 获取部门编号
String deptno = request.getParameter("deptno");
// 连接数据库,根据部门编号查询部门信息。
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select dname,loc as location from dept where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, deptno);
rs = ps.executeQuery();
// 这个结果集只有一条记录。
if (rs.next()) {
String dname = rs.getString("dname");
String loc = rs.getString("location"); // 参数"location"是sql语句查询结果列的列名。
out.print("部门编号
");
out.print("部门名称
");
out.print("部门位置
");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
out.print("
");
out.print(" ");
out.print(" ");
out.print("");
}
}
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DeptModifyServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决请求体的中文乱码问题
request.setCharacterEncoding("UTF-8");
// 获取表单中的数据
String deptno = request.getParameter("deptno");
String dname = request.getParameter("dname");
String loc = request.getParameter("loc");
// 连接数据库执行更新语句
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
conn = DBUtil.getConnection();
String sql = "update dept set dname = ?, loc = ? where deptno = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, dname);
ps.setString(2, loc);
ps.setString(3, deptno);
count = ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(conn, ps, null);
}
if (count == 1) {
// 更新成功
// 跳转到部门列表页面(部门列表页面是通过Java程序动态生成的,所以还需要再次执行另一个Servlet)
request.getRequestDispatcher("/dept/list").forward(request, response);
} else {
request.getRequestDispatcher("/error.html").forward(request, response);
}
}
}
// 获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/dept/list");
// 调用请求转发器对象的forward方法完成转发
dispatcher.forward(request, response);
// 合并一行代码
request.getRequestDispatcher("/dept/list").forward(request, response);
// 转发的时候是一次请求,不管你转发了多少次,都是一次请求。
// AServlet转发到BServlet,再转发到CServlet,再转发到DServlet,不管转发了多少次,都在同一个request当中。
// 这是因为调用forward方法的时候,会将当前的request和response对象传递给下一个Servlet。
- 重定向
// 注意:路径上要加一个项目名。为什么?
// 浏览器发送请求,请求路径上是需要添加项目名的。
// 以下这一行代码会将请求路径“/oa/dept/list”发送给浏览器
// 浏览器会自发的向服务器发送一次全新的请求:/oa/dept/list
response.sendRedirect("/oa/dept/list");
// 所以浏览器一共发送了两次请求。
// 最终浏览器地址栏上显示的地址当然是最后那一次请求的地址。所以重定向会导致浏览器地址栏上的地址发生改变
jakarta.servlet.annotation.WebServlet
package com.bjpowernode.javaweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
@WebServlet(name = "hello",urlPatterns = {"/hello1","/hello2"},
// loadOnStartup = 1,
initParams = {@WebInitParam(name = "user",value = "root"),@WebInitParam(name = "password",value = "123456")})
public class HelloServlet extends HttpServlet {
}
package com.bjpowernode.oa.web.action;
import com.bjpowernode.oa.utils.DBUtil;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// 模板类
@WebServlet({"/dept/list", "/dept/save", "/dept/edit", "/dept/detail", "/dept/delete", "/dept/modify"})
// 模糊匹配
//@WebServlet("/dept/*")
public class DeptServlet extends HttpServlet {
// 模板方法
// 重写service方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取servlet path
String servletPath = request.getServletPath();
if ("/dept/list".equals(servletPath)) {
doList(request, response);
} else if ("/dept/save".equals(servletPath)) {
doSave(request, response);
} else if ("/dept/edit".equals(servletPath)) {
doEdit(request, response);
} else if ("/dept/detail".equals(servletPath)) {
doDetail(request, response);
} else if ("/dept/delete".equals(servletPath)) {
doDel(request, response);
} else if ("/dept/modify".equals(servletPath)) {
doModify(request, response);
}
}
private void doList(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
private void doSave(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
private void doEdit(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
private void doDetail(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
private void doDel(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
private void doModify(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
}
@WebServlet({"/test/session"})
public class TestSessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// request和session都是服务器端的java对象。都在JVM当中。
// request对象代表了一次请求。(一次请求对应一个request对象。两次请求就会对应两个不同的request对象。)
// session对象代表了一次会话。(一次会话对应一个session对象。)
// 获取session对象
// 从WEB服务器当中获取session对象,如果session对象没有,则新建。
HttpSession session = request.getSession();
// 将session对象响应到浏览器。
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.print("会话对象:" + session);
}
}
<session-config>
<session-timeout>30session-timeout>
session-config>
response.addCookie(cookie);
cookie.setMaxAge(60 * 60);
设置cookie在一小时之后失效。cookie.setPath("/servlet13");
表示只要是这个servlet13项目的请求路径,都会提交这个cookie给服务器。Cookie[] cookie = request.getCookies(); // 这个方法可能返回null
if(cookies != null){
for(Cookie cookie : cookies){
// 获取cookie的name
String name = cookie.getName();
// 获取cookie的value
String value = cookie.getValue();
}
}
@WebServlet("/welcome")
public class WelcomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取cookie
Cookie[] cookies = request.getCookies();
String username = null;
String password = null;
if (cookies != null) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
if ("username".equals(name)) {
username = cookie.getValue();
} else if ("password".equals(name)) {
password = cookie.getValue();
}
}
}
if (username != null && password != null) {
// 验证用户名和密码是否正确
// 正确,表示登录成功
// 错误,表示登录失败
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
boolean success = false;
try {
conn = DBUtil.getConnection();
String sql = "select * from t_user where username = ? and password = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
if (rs.next()) {
// 登录成功
success = true;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
if (success) {
HttpSession session = request.getSession();
session.setAttribute("username", username);
// 正确,表示登录成功
response.sendRedirect(request.getContextPath() + "/dept/list");
} else {
// 错误,表示登录失败
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
} else {
// 跳转到登录页面
response.sendRedirect(request.getContextPath() + "/index.jsp");
}
}
}
<%@page contentType="text/html;charset=UTF-8"%>
,表示响应的内容类型是text/html,采用的字符集UTF-8<%@page import="java.util.List,java.util.ArrayList"%>
<% java语句; %>
<%! %>
<%= %>
注意:在=后面编写要输出的内容。out.print();
<%
String username = "jack";
%>
<%="登录成功,欢迎" + username %> <%-- out.print("登录成功,欢迎" + username); --%>
<%--JSP的专业注释,不会被翻译到java源代码当中。--%>
<servlet-mapping>
<servlet-name>jspservlet-name>
<url-pattern>*.jspurl-pattern>
<url-pattern>*.jspxurl-pattern>
servlet-mapping>
- xxx.jsp文件对于小猫咪来说,只是一个普通的文本文件,web容器会将xxx.jsp文件最终生成java程序,最终调用的是java对象相关的方法,真正执行的时候,和jsp文件就没有关系了。
- 小窍门:JSP如果看不懂,建议把jsp翻译成java代码,你就看懂了。
<%@指令名 属性名=属性值 属性名=属性值 属性名=属性值...%>
<%@page session="true|false" %>
true表示启用JSP的内置对象session,表示一定启动session对象。没有session对象会创建。
如果没有设置,默认值就是session="true"
session="false" 表示不启动内置对象session。当前JSP页面中无法使用内置对象session。
<%@page contentType="text/json" %>
contentType属性用来设置响应的内容类型
但同时也可以设置字符集
<%@page contentType="text/json;charset=UTF-8" %>
<%@page pageEncoding="UTF-8" %>
pageEncoding="UTF-8" 表示设置响应时采用的字符集。
<%@page import="java.util.List, java.util.Date, java.util.ArrayList" %>
<%@page import="java.util.*" %>
import语句,导包。
<%@page errorPage="/error.jsp" %>
当前页面出现异常之后,跳转到error.jsp页面。
errorPage属性用来指定出错之后的跳转位置。
<%@page isErrorPage="true" %>
表示启用JSP九大内置对象之一:exception
默认是false。
-------------------------------------------------------------------
例子:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page isErrorPage="true" %>
error
网络繁忙,稍后再试!!!
<%--打印异常堆栈信息,输出到后台控制台。exception是九大内置对象之一。--%>
<%
exception.printStackTrace();
%>
<%
// 创建User对象
User user = new User();
user.setUsername("jackson");
user.setPassword("1234");
user.setAge(50);
// 将User对象存储到某个域当中。一定要存,因为EL表达式只能从某个范围中取数据。
// 数据是必须存储到四大范围之一的。
request.setAttribute("userObj", user);
%>
<%--使用EL表达式取数据--%>
${这个位置写什么?这里写的一定是存储到域对象当中时的name}
要这样写:
${userObj}
等同于java代码:<%=request.getAttribute("userObj")%>
不要这样写:${"userObj"}
面试题:
${abc} 和 ${"abc"} 的区别是什么?
${abc} 表示从某个域中取出数据,并且被取得这个数据的name是“abc”,之前一定有这样的代码:域.setAttribute("abc", 对象);
${"abc"} 表示直接将“abc”当作普通字符串输出到浏览器。不会从某个域中取数据了。
${userObj} 底层是怎么做的? 从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器。
<%--如果想输出对象的属性值,怎么办?--%>
${userObj.username} 使用这个语法的前提是:User对象有getUsername()方法。
${userObj.password} 使用这个语法的前提是:User对象有getPassword()方法。
${userObj.age} 使用这个语法的前提是:User对象有getAge()方法。
${userObj.email} 使用这个语法的前提是:User对象有getEmail()方法。
EL表达式中的 . 这个语法,实际上调用了底层的getXxxx()方法。
注意:如果没有对应的get方法,则出现异常。报500错误。
${userObj.addr222.zipcode}
以上EL表达式对应的java代码:
user.getAddr222().getZipcode()
<%@page contentType="text/html;charset=UTF-8" isELIgnored="true" %>
isELIgnored="true" 表示忽略EL表达式
isELIgnored="false" 表示不忽略EL表达式。(这是默认值)
isELIgnored="true" 这个是全局的控制。
可以使用反斜杠进行局部控制:\${username} 这样也可以忽略该EL表达式。
<%@page contentType="text/html;charset=UTF-8" %>
<%--<%@page import="javax.servlet.http.HttpServletRequest" %>--%>
<%--
JSP有九大内置对象
pageContext request session application response out config page exception
其中四个域对象,其中最小的域是pageContext
pageContext翻译为:页面上下文。通过pageContext可以获取什么?
--%>
<%--从以下代码来看,pageContext.getRequest() 方法是没用的,这是获取request对象。而JSP中自带了内置对象request,直接用request内置对象就行了。--%>
<%=pageContext.getRequest()%>
<%=request%>
<%--
在EL表达式当中没有request这个隐式对象。
requestScope 这个只代表”请求范围“。不等同于request对象。
在EL表达式当中有一个隐式的对象:pageContext
EL表达式中的pageContext和JSP中的九大内置对象pageContext是同一个对象。
--%>
<%=((HttpServletRequest) pageContext.getRequest()).getContextPath() %>
这段java代码对应的EL表达式:
使用EL表达式来获取应用的根路径:
${pageContext.request.contextPath}
<%@page contentType="text/html;charset=UTF-8" %>
<%--
JSP中EL表达式的隐含对象:
1. pageContext
2. param
3. paramValues
4. initParam
5. 其他(不是重点)
--%>
应用的根路径:${pageContext.request.contextPath}
<%--request是JSP九大内置对象之一。--%>
<%--用户在浏览器上提交数据:http://localhost:8080/jsp/15.jsp?username=zhangsan--%>
用户名:<%=request.getParameter("username")%>
用户名:${param.username}
<%--假设用户提交的数据:http://localhost:8080/jsp/15.jsp?username=zhangsan&aihao=zuqiu&aihao=lanqiu&aihao=youyong--%>
<%--以上提交的数据显然是采用checkbox进行提交的。同一组的checkbox的name是一样的。--%>
<%--param 获取的是请求参数一维数组当中的第一个元素。--%>
爱好:${param.aihao}
爱好:<%=request.getParameter("aihao")%>
一维数组:${paramValues.aihao}
一维数组:<%=request.getParameterValues("aihao")%>
<%--获取数组当中的元素:[下标]--%>
爱好:${paramValues.aihao[0]}、${paramValues.aihao[1]}、${paramValues.aihao[2]}
<%--EL表达式中的隐含对象:initParam--%>
<%--ServletContext是Servlet上下文对象,对应的JSP九大内置对象之一是:application --%>
<%
String pageSize = application.getInitParameter("pageSize");
String pageNum = application.getInitParameter("pageNum");
%>
每页显示的记录条数:<%=pageSize%>
页码:<%=pageNum%>
每页显示的记录条数:<%=application.getInitParameter("pageSize")%>
页码:<%=application.getInitParameter("pageNum")%>
每页显示的记录条数:${initParam.pageSize}
页码:${initParam.pageNum}
${10 + 20}
<%--30--%>
<%--在EL表达式中”+“运算符只能做求和运算。不会进行字符串的拼接操作。--%>
<%--”20“会被自动转成数字20--%>
${10 + "20"}
<%--30--%>
<%--java.lang.NumberFormatException: For input string: "abc"--%>
<%-- + 两边不是数字的时候,一定会转成数字。转不成数字就报错:NumberFormatException--%>
\${10 + "abc"}
\${"king" + "def"}
<%--关系运算符--%>
${"abc" == "abc"}
<%--true--%>
${"abc"} == ${"abc"}
<%
Object obj = new Object();
request.setAttribute("a", obj);
request.setAttribute("b", obj);
%>
${a == b}
<%--true--%>
<%
String s1 = new String("hehe");
String s2 = new String("hehe");
request.setAttribute("s1", s1);
request.setAttribute("s2", s2);
%>
${s1 == s2}
<%--true--%>
<%
Object o1 = new Object();
Object o2 = new Object();
request.setAttribute("o1", o1);
request.setAttribute("o2", o2);
%>
${o1 == o2}
<%--false--%>
<%
Student stu1 = new Student("110", "警察");
Student stu2 = new Student("110", "警察");
request.setAttribute("stu1", stu1);
request.setAttribute("stu2", stu2);
%>
<%--EL表达式当中的“==”调用了equals方法。--%>
${stu1 == stu2}
<%--true--%>
${stu1 eq stu2}
<%--true--%>
<%--以下语法错误,没有加小括号。javax.el.ELException --%>
\${!stu1 eq stu2}
<%--报错了--%>
<%--正确的--%>
${!(stu1 == stu2)}
<%--false--%>
${not(stu1 == stu2)}
<%--false--%>
<%--条件运算符--%>
${empty param.username}
<%--empty运算符:运算结果是boolean类型。--%>
<%--判断是否为空,如果为空,结果是true。如果不为空,结果是false。--%>
${empty param.username}
${!empty param.username}
${not empty param.username}
<%--永远是false,因为前半部分是boolean类型,后面是null--%>
${empty param.password == null}
<%--false--%>
${(empty param.password) == null}
<%--false--%>
${param.password == null}
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
这个就是核心标签库。
prefix="这里随便起一个名字就行了,核心标签库,大家默认地叫做c,你随意。"
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
以上uri后面的路径实际上指向了一个xxx.tld文件。
tld文件实际上是一个xml配置文件。
在tld文件中描述了“标签”和“java类”之间的关系。
以上核心标签库对应的tld文件是:c.tld文件。它在哪里:
在taglibs-standard-impl-1.2.5.jar里面的META-INF目录下,有一个c.tld文件。
<tag>
<description>对该标签的描述description>
<name>catchname> 标签的名字
<tag-class>org.apache.taglibs.standard.tag.common.core.CatchTagtag-class> 标签对应的java类。
<body-content>JSPbody-content> 标签体当中可以出现的内容,如果是JSP,就表示标签体中可以出现符合JSP所有语法的代码,例如EL表达式。
<attribute>
<description>
对这个属性的描述
description>
<name>varname> 属性名
<required>falserequired> false表示该属性不是必须的。true表示该属性是必须的。
<rtexprvalue>falsertexprvalue> 这个描述说明了该属性是否支持EL表达式。false表示不支持。true表示支持EL表达式。
attribute>
tag>
<%@ page import="com.bjpowernode.javaweb.jsp.bean.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@page contentType="text/html;charset=UTF-8" %>
<%--引入标签库。这里引入的是jstl的核心标签库。--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--格式化标签库,专门负责格式化操作的。--%>
<%--<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>--%>
<%--sql标签库--%>
<%--<%@taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>--%>
<%
// 创建List集合
List<Student> stuList = new ArrayList<>();
// 创建Student对象
Student s1 = new Student("110", "警察");
Student s2 = new Student("120", "救护车");
Student s3 = new Student("119", "消防车");
// 添加到List集合中
stuList.add(s1);
stuList.add(s2);
stuList.add(s3);
// 将list集合存储到request域当中
request.setAttribute("stuList", stuList);
%>
<%--需求:将List集合中的元素遍历。输出学生信息到浏览器--%>
<%--使用java代码--%>
<%
// 从域中取出list集合
List<Student> stus = (List<Student>) request.getAttribute("stuList");
// 编写for循环遍历list集合
for (Student student : stus) {
%>
id:<%=student.getId()%>,name:<%=student.getName()%><br>
<%
}
%>
<hr>
<%--使用core标签库中forEach标签。对List集合进行遍历--%>
<%--EL表达式只能从域中取数据。--%>
<%--var后面的名字是随意的。var属性代表的是集合中的每一个元素。--%>
<c:forEach items="${stuList}" var="s">
id:${s.id},name:${s.name}<br>
c:forEach>
<%@page contentType="text/html;charset=UTF-8" %>
<%--引入核心标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--核心标签库中的if标签--%>
<%--test属性是必须的。test属性支持EL表达式。test属性值只能是boolean类型。--%>
<c:if test="${empty param.username}">
<h1>用户名不能为空。h1>
c:if>
<%--没有else标签的话,可以搞两个if出来。--%>
<%--if标签还有var属性,不是必须的。--%>
<%--if标签还有scope属性,用来指定var的存储域,也不是必须的。--%>
<%--scope有四个值可选:page(pageContext域)、request(request域)、session(session域)、application(application域)--%>
<%--将var中的v存储到request域。--%>
<c:if test="${not empty param.username}" var="v" scope="request">
<h1>欢迎你${param.username}h1>
c:if>
<hr>
<%--通过EL表达式将request域当中的v取出--%>
<%--v变量中存储的是test属性的值。--%>
${v}
${元素状态对象.count}
${i}
<%@ page import="com.bjpowernode.javaweb.jsp.bean.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.List" %>
<%@page contentType="text/html; charset=UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--var用来指定循环中的变量--%>
<%--begin开始--%>
<%--end结束--%>
<%--step步长--%>
<%--底层实际上:会将i存储到pageContext域当中。--%>
<c:forEach var="i" begin="1" end="10" step="2">
<%--所以这里才会使用EL表达式将其取出,一定是从某个域当中取出的。--%>
${i}<br>
c:forEach>
<%
// 创建List集合
List<Student> stuList = new ArrayList<>();
// 创建Student对象
Student s1 = new Student("110", "警察");
Student s2 = new Student("120", "救护车");
Student s3 = new Student("119", "消防车");
// 添加到List集合中
stuList.add(s1);
stuList.add(s2);
stuList.add(s3);
// 将list集合存储到request域当中
request.setAttribute("stuList", stuList);
%>
<hr>
<%--var="s" 这个s代表的是集合中的每个Student对象--%>
<%--varStatus="这个属性表示var的状态对象,这里是一个java对象,这个java对象代表了var的状态"--%>
<%--varStatus="这个名字是随意的"--%>
<%--varStatus这个状态对象有count属性。可以直接使用。--%>
<c:forEach items="${stuList}" var="s" varStatus="stuStatus">
<%--varStatus的count值从1开始,以1递增,主要是用于编号/序号。--%>
编号:${stuStatus.count},id:${s.id},name:${s.name}<br>
c:forEach>
使用什么技术改造呢?
在前端HTML代码中,有一个标签,叫做base标签,这个标签可以设置整个网页的基础路径。
这不是java的语法,也不是JSP的语法。是HTML中的一个语法,HTML中的一个标签,通常出现在head标签中。
在当前页面中,凡是路径没有以“/”开始的,都会自动将base中的路径添加到这些路径之前。
需要注意:在JS代码中的路径,保险起见,最好不要依赖base标签。JS代码中的路径最好写上全路径。
package com.bjpowernode.javaweb.servlet;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
//@WebFilter("/abc")
//@WebFilter("/a.do")
//@WebFilter({"/a.do", "/b.do"})
/*以下这个路径属于模糊匹配中的扩展匹配。以星号开始,注意这种路径不要以/开始。*/
@WebFilter("*.do")
/*属于前缀匹配。要以/开始。*/
//@WebFilter("/dept/*")
/*匹配所有的路径。*/
//@WebFilter("/*")
public class Filter1 implements Filter {
public Filter1() {
System.out.println("无参数构造方法执行了。");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init方法执行。");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 在请求的时候添加过滤规则。
System.out.println("Filter1 doFilter方法开始执行。");
// 执行下一个过滤器,如果下一个不是过滤器了,则执行目标程序Servlet。
// 向下走。没有它是不行滴。
chain.doFilter(request, response);
// 在响应的时候添加过滤规则。
System.out.println("Filter1 doFilter方法执行结束。");
}
@Override
public void destroy() {
System.out.println("destroy方法执行。");
}
}
<filter>
<filter-name>filter1filter-name>
<filter-class>com.bjpowernode.javaweb.servlet.Filter1filter-class>
filter>
<filter-mapping>
<filter-name>filter1filter-name>
<url-pattern>*.dourl-pattern>
filter-mapping>
- 或者使用注解:@WebFilter({"*.do"})
package com.bjpowernode.javaweb.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
//ServletContextListener监听器主要监听的是:ServletContext对象的状态。
@WebListener
public class MyServletContextListener implements ServletContextListener {
/**
* 监听器中的方法不需要程序员手动调用。是发生某个特殊事件之后被服务器调用。
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) { // 服务器启动时间点,想在这个时候执行一段代码,写就行了。
// 先在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
// 这个方法是在ServletContext对象被创建的时候调用。
System.out.println("ServletContext对象创建了。");
}
@Override
public void contextDestroyed(ServletContextEvent sce) { // 服务器关闭时间点。
// 先在这个特殊的时刻写代码,你写就是了。它会被服务器自动调用。
// 这个方法是在ServletContext对象被销毁的时候调用。
System.out.println("ServletContext对象被销毁了。");
}
}
<listener>
<listener-class>com.bjpowernode.javaweb.listener.MyServletContextListenerlistener-class>
listener>
- 当然,第二步也可以不使用配置文件,也可以用注解,例如:**@WebListener**